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); // 详述的类型 } |
explicit | 用法
explicit | (1) | | explicit (?表达式?) | (2) | (C++20 起) |
1)?指定构造函数或转换函数?(C++11 起)或推导指引?(C++17 起)为显式,即它不能用于隐式转换和复制初始化。
2)?explicit?说明符可以与常量表达式一同使用。当且仅当该常量表达式求值为?true?时函数为显式。 | (C++20 起) |
explicit 说明符只可出现于在类定义之内的构造函数或转换函数?(C++11 起)的?声明说明符序列?中。 ? | 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 进行直接初始化 } |
friend 说明 友元声明出现于类体内,并向一个函数或另一个类授予对包含友元声明的类的私有及受保护成员的访问权。 | 语法
friend?函数声明 | (1) | | friend?函数定义 | (2) | | friend?详述类说明符?; | (3) | | friend?简单类型说明符?; friend?typename-说明符?; | (4) | (C++11 起) |
| |
inline 说明: | 用法
| |
export 用法
用于标记模板定义为被导出,这允许在其他翻译单元中声明但不定义同一模板。(1) | (C++11 前) | 不使用并保留该关键词。 | (C++11 起) (C++20 前) | 标记一个声明、一组声明或另一模块为当前模块所导出。 | (C++20 起) |
| export 是可选的修饰符,模板被导出(用于声明类模板时,它也声明其所有成员被导出)。对被导出模板进行实例化的文件不需要包含其定义:声明即已充分。 export module name
- 导出模块
- export?template?<?形参列表?>?类声明
| (1) export template <typename T> class MyClass { ??? public: ??????? void memfun1();???? // 被导出的函数 ??????? void memfun2(){ ... } // 隐式内联不能被导出 ??????? ... ??????? void memfun3();????? // 显式内联不能被导出 ??????? ... }; template <typename T> inline void MyClass<T>::memfun3()?? // 使用inline关键字,显式内联 { ??? ... } (2) // helloworld.cpp export module helloworld;? // 模块声明 import <iostream>;???????? // import声明 ? export void hello() {????? // export声明 ??? std::cout << "Hello world!\n"; } // main.cpp import helloworld;? // import声明 ? int main() { ??? hello(); } |
extern 用法
|
extern?字符串字面量?{?声明序列(可选)?} | (1) | extern?字符串字面量?声明 | (2) |
1)?将语言说明?字符串字面量?应用到声明于?声明序列?中的所有函数类型,具有外部链接的函数名,和具有外部链接的变量。 2)?将语言说明?字符串字面量?应用到单一声明或定义。
字符串字面量 | - | 所要求的语言链接的名字 | 声明序列 | - | 声明的序列,可以包含嵌套的链接说明 | 声明 | - | 一个声明 |
extern?template?class|struct?模板名?<?实参列表?>?;? (C++11 起)
- 显示模板实例化声明
- "C++",默认的语言链接。
- "C",使得以 C 程序语言编写的函数进行链接,以及在 C++ 程序中定义能从 C 模块调用的函数成为可能。
- 外部链接声明
- 提供以不同程序语言编写的模块间的链接。
| (1) (2) 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++ } |
concept(C++20 起) 约束与概念: (1) 类模板,函数模板,以及非模板函数(常为类模板的成员),可以与约束(constraint)关联,它指定对模板实参的一些要求,这些要求可被用于选择最恰当的函数重载和模板特化。 (2) 这种要求的具名集合被称为概念(concept)。每个概念都是谓词,于编译时求值,并成为以之作为一项约束的模板接口的一部分: | | ? |
const 说明: | 用法
| ? |
consteval(c++20) 说明:
- consteval?- 指定函数是立即函数(immediate function),即每次调用该函数必须产生编译时常量。
? | ? | consteval int sqr(int n) { ? return n*n; } constexpr int r = sqr(100);? // OK int x = 100; int r2 = sqr(x);? // 错误:调用不产生常量 |
constexpr(c++11) 说明: constexpr 说明符声明 可以 在编译时求 得 函数 或变量的 值。 然后这些 变量和函数(若给定了合适的函数实参)即可用于仅允许编译时常量表达式之处。 | constexpr?变量必须满足下列要求: constexpr?函数必须满足下列要求:
| (C++14 前) |
(=default;?或?=delete;?的函数体不含任何上述内容。)
- 非字面类型的变量定义
- 静态或线程存储期变量的定义
- 函数体必须不含:
- 拥有除?case?和?default?之外的标号的语句
| (C++14 起) |
函数体非?=delete;?的?constexpr?构造函数必须满足下列额外要求:
析构函数不能为?constexpr?,但能在常量表达式中调用平凡析构函数。 | (C++20 前) | 函数体非?=delete;?的?constexpr?析构函数必须满足下列额外要求:
- 每个用于销毁非静态数据成员与基类的析构函数必须为 constexpr 析构函数。
| (C++20 起) |
对于?constexpr?函数模板和类模板的?constexpr?函数成员,必须至少有一个特化满足上述要求。其他特化仍被认为是 constexpr,尽管常量表达式中不能出现这种函数的调用。 带初始化器的 if 语句
| (1) constexpr int factorial(int n) { ??? return n <= 1? 1 : (n * factorial(n - 1)); } (2) 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 } |
constinit(c++20) 说明: 说明符声明拥有静态或线程存储期的变量。 constinit 不能和 constexpr 或 consteval 一同使用。声明的变量为引用时, constinit 等价于 constexpr 。声明的变量为对象时, constexpr 强制对象必须拥有静态初始化和常量析构,并使对象有 const 限定,然而 constinit 不强制常量析构和 const 限定。 | | (1)初始化声明 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); // 错误 (2)用于非初始化声明,以告知编译器 thread_local 变量已被初始化。 extern thread_local constinit int x; int f() { return x; } // 无需检查防卫变量 |
const_cast:见类型转换 dynamic_cast:见类型转换 |
const_cast?<?新类型?>?(?表达式?) |
dynamic_cast?<?新类型?>?(?表达式?) |
|
| |
? | ? | |
alignas(c++11) 头文件:<stdalign.h> 与 <cstdalign> 说明:指定类型或对象的对齐要求。说明符可应用于变量或非位域类数据成员的 声明,或可应用于 class/struct/union 或枚举的定义。它不能应用于函数形参 或 catch 子句的异常形参。同一声明上,弱于其他 alignas 的有效的非零对齐被忽略。始终忽略 alignas(0)。 | alignas( 表达式 ):必须是求值为零或合法的对齐或扩展对齐的整型常量表达式。 alignas( 类型标识 ):等价于 alignas(alignof(类型)) alignas( 包 ... ):等价于对同一说明应用多个 alignas 说明符,逐个对应于形参包的各个成员, 形参包可以是类型或非类型形参包。 | // sse_t 类型的每个对象将对齐到 16 字节边界 struct alignas(16) sse_t { ? float sse_data[4]; }; // 数组 "cacheline" 将对齐到 128字节边界 alignas(128) char cacheline[128]; |
alignof 运算符(c++11) 头文件: 说明:查询类型的对齐要求。该类型可以为完整对象类型、元素类型完整的数组类型或者到这些类型之一 的引用类型。若类型为引用类型,则运算符返回被引用类型的对齐;若类型为数组类型, 则返回元素类型的对齐要求。 | alignof(?类型标识?):返回std::size_t类型的值 | #include <iostream> struct Foo { ??? int?? i; ??? float f; ??? char? c; }; struct Empty {}; struct alignas(64) Empty64 {}; int main() { ??? std::cout << "Alignment of"? "\n"?? "- char???????????? : " << alignof(char)??? << "\n" ??????? "- pointer????????? : " << alignof(int*)??? << "\n" ??????? "- class Foo??????? : " << alignof(Foo)???? << "\n" ??????? "- empty class????? : " << alignof(Empty)?? << "\n" ??????? "- alignas(64) Empty: " << alignof(Empty64) << "\n"; } |
std::max_align_t(c++11) 头文件:<cstddef> 说明:std::max_align_t 通常是最大标量类型的同意词,在大多数平台上是 long double ,而其对齐要求是 8 或 16 。 | ? | #include <iostream> #include <cstddef> int main() { ??? std::cout << alignof(std::max_align_t) << '\n'; } >> 16 |
and and_eq bitand bitor compl not not_eq or or_eq xor xor_eq <% %> <: :> %: %:%: | &&???????? &=???????? &???????? |???????? ~???????? !???????? !=???????? ||???????? |=???????? ^???????? ^=???????? {???????? }???????? [???????? ]???????? #???????? ##???????? | if(n > 0 and n < 5) value? and_eq data; |
asm 说明:给予在 C++ 程序中嵌入汇编语言源代码的能力。 | asm (?字符串字面量?)?: 字符串字面量 通常是以汇编语言编写的短程序,每当执行这条声明时对其执行。 | |
atomic_cancel (TM TS) atomic_commit (TM TS) atomic_noexcept (TM TS) 说明: | 事务性内存(transactional memory):是在事务中结合语句组的并发同步机制,事务具有: 原子性(atomic)(要么语句全部发生,要么全部不发生) 隔离性(isolated)(事务中的语句不会观察到另一事务写入一半,即使它们并行执行) 同步块synchronized 复合语句 (1)如同在一个全局锁下执行复合语句:程序中的所有最外层同步块都以一个单独的全序执行。 在该顺序中,每个同步块的结尾同步于(synchronize with)下个同步块的开始。内嵌于其 他同步块的同步块没有特殊语义。同步块不是事务(不同于后面的原子块),并可以调用事务不安全的函数。 (2)以任何方式(抵达结尾,执行 goto、break、continue 或 return,或抛出异常)离开同步块都会退出该块, 而若所退出的块是外层块,则这在单一全序中同步于下个同步块。 不允许用 goto 或 switch 进入同步块。 原子块: 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 的函数(这是编译时错误)。 (4)以除异常之外的任何方式(抵达结尾、goto、break、continue、return)离开原子块时,将提交事务。若用 std::longjmp 退出原子块则行为未定义。 事务安全的函数: 可在函数声明中用关键词?transaction_safe?将其显式声明为事务安全。 | (1) #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 (2) // 每次调用 f() 都取得 i 的唯一值,即使以并行进行 int f() { ?? static int i = 0; ?? atomic_noexcept { // 开始事务 //?? printf("before?%d\n", i); // 错误:不能调用非事务安全的函数 ????? ++i; ????? return i; // 提交事务 ?? } } |
auto (1)类型推导C++11 起: 对于变量,指定要从其初始化器自动推导出其类型。 对于函数,指定要从其 return 语句推导出其返回类型。(C++14 起) 对于非类型模板形参,指定要从实参推导出其类型。(C++17 起) (2):带尾随返回类型的函数声明: 尾随返回类型仅在最外层函数声明符中允许使用。此情况下的 声明说明符序列 必须包含关键词 auto (3)结构化绑定声明 见:结构化绑定声明(c++17) | (1) auto (1) (C++11 起) decltype(auto) (2) (C++14 起) 类型制约?auto (3) (C++20 起) 类型制约?decltype(auto) (4) (C++20 起) (2) auto 说明符亦可用于后随尾随返回类型的函数声明符,该情况下返回类型为其尾随返回类型(它也可以是占位符类型): auto (*p)() -> int; // 声明指向返回 int 的函数的指针 尾随返回类型,当返回类型取决于实参名时,例如 template <class T, class U> auto add(T t, U u) -> decltype(t + u);,或当返回类型复杂时,例如在 auto fpif(int)->int(*)(int) 中,尾随返回类型很有用 若函数声明的 声明说明符序列 包含关键词 auto,则尾随返回类型可以省略,而编译器将从 return 语句中所用的表达式的类型推导出它。若返回类型使用的不是 decltype(auto),则推导遵循模板实参推导的规则进行。 | (1) template<class T, class U> auto add(T t, U u) { return t + u; } // 返回类型是 operator+(T, U) 的类型 (2) // 在其所调用的函数返回引用的情况下 // 函数调用的完美转发必须用 decltype(auto) template<class F, class... Args> decltype(auto) PerfectForward(F fun, Args&&... args) { ??? return fun(std::forward<Args>(args)...); } (3) template<auto n> // C++17 auto 形参声明 auto f() -> std::pair<decltype(n), decltype(n)> // auto 不能从花括号初始化器列表推导 { ??? return {n, n}; } |
bool/break/switch/case/continue/switch/do/if/enum/false/for/goto | 常规操作 | |
char/char8_t(c++20)/char16_t(c++20)/char32_t(c++20)/double/float/int/long/short | ? | |
default | 用法 类名()?=?default?;
| |
? | ::(可选)????delete ???表达式 ::(可选)????delete []?表达式 如果取代函数体而使用特殊语法?= delete?;,则该函数被定义为弃置的(deleted)。任何弃置函数的使用都是非良构的(程序无法编译)。 类名()?=?delete?;
| |
try-catch: 说明:将一或多个异常处理块(catch 子句)与复合语句关联。 | 语法
try?复合语句?处理块序列?? 其中?处理块序列?是一或多个?处理块?的序列,它有下列语法: |
catch?(?attr(可选)?类型说明符序列?声明符?)?复合语句 | (1) | catch?(?attr(可选)?类型说明符序列?抽象声明符(可选)?)?复合语句 | (2) | catch?(?...?)?复合语句 | (3) |
| |
? | ? | |
协程: 协程是能暂停执行以在之后恢复的函数。协程是无栈的:它们通过返回到调用方暂停执行,并且从栈分离存储恢复所要求的数据。这允许编写异步执行的顺序代码(例如不使用显式的回调来处理非阻塞 I/O),还支持对惰性计算的无限序列上的算法及其他用途。 若函数的定义做下列任何内容之一,则它是协 co_wait(c++20)
co_yield(c++20)
co_return(c++20)
- 用关键词?co_return?完成执行并返回一个值
| ? | |
decltype(c++11) 说明:在难以或不可能以标准写法进行声明的类型时,decltype 很有用,例如 lambda 相关类型或依赖于模板形参的类型。 | 语法
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。 注意如果对象的名字带有括号,则它被当做通常的左值表达式,从而 decltype(x) 和 decltype((x)) 通常是不同的类型。
decltype(auto)????? (C++14 起) | | | 类型制约?decltype(auto)??? (C++20 起) | ? | ? |
- 占位类型说明符
- 检查实体的声明类型,或表达式的类型和值类别。
| #include <iostream> 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; } |
enum 语法: enum-关键词?attr(可选)?enum-名(可选)?enum-基(可选)(C++11)?{?枚举项列表(可选)?} (1) enum-关键词?attr(可选)?enum-名?enum-基(可选)?;?? (2)(C++11 起) ? |
enum-关键字 | : | enum、enum class(C++11 起)?或?enum struct(C++11 起)?之一 | attr(C++11) | - | 任意数量的属性的可选序列 | enum-名 | - | 所声明的枚举的名字。若存在,且若此声明为重声明,则其之前可带有?嵌套名说明符(C++11 起),即名字和作用域解析运算符?::?的序列并以作用域解析运算符结尾。仅可在无作用域枚举声明中省略名字 | enum-基(C++11) | - | 冒号 (:),后随指名某个整型类型的?类型说明符序列(若它为 cv 限定,则忽略其限定性),该类型将作为此枚举类型的固定底层类型 | 枚举项列表 | - | 枚举项定义的逗号分隔列表,每项要么是简单的?标识符,它成为枚举项之名,要么是带初始化器的标识符:标识符?=?常量表达式。 |
有两种截然不同的枚举:无作用域枚举(以?enum-关键词?enum?声明)和有作用域枚举(以?enum-关键词?enum class?或?enum struct?声明)。
enum?名字?{?枚举项?=?常量表达式?,?枚举项?=?常量表达式?,?...?} | (1) | | enum?名字?:?类型?{?枚举项?=?常量表达式?,?枚举项?=?常量表达式?,?...?} | (2) | (C++11 起) | enum?名字?:?类型?; | (3) | (C++11 起) |
1)?声明无作用域枚举类型,其底层类型不固定(此情况中,底层类型是由实现定义的某个能表示所有枚举项值的整型类型;此类型不大于?int,除非枚举项的值不能放入?int?或?unsigned int。若?枚举项列表?为空,则底层类型为如同枚举拥有单个值为 0 的枚举项)。 2)?声明底层类型固定的无作用域枚举类型。 3)?无作用域枚举的不可见枚举声明必须指定底层类型。 每个?枚举项?都成为该枚举类型(即?名字)的一个具名常量,在其外围作用域可见,且可用于要求常量的任何位置。整数、浮点和枚举类型的值,可用?static_cast?或显式转型转换到任何枚举类型。 无作用域枚举的?名字?可以忽略:这种声明仅将各枚举项引入到其外围作用域中:
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?可用于获得枚举项的数值。
using?enum?嵌套名说明符(可选)?名字?; | (C++20 起) |
using enum 声明引入其所指名的枚举的枚举项名字,如同用对每个枚举项的?using 声明。在类作用域中时, using enum 声明将其所指名的枚举的枚举项名字作为成员添加到作用域,使成员查找能访问它们 ? | (1)无作用域枚举 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); // C++17 起为未定义行为 access_t y = static_cast<access_t>(8); // C++17 起为未定义行为 ? enum foo { a = 0, b = UINT_MAX }; // 范围:[0, UINT_MAX] foo x= foo(-1); // C++17 起为未定义行为,即使 foo 的底层类型为 unsigned int (2)有作用域枚举 enum class Color { red, green = 20, blue }; Color r = Color::blue; switch(r) { ??? case Color::red? : std::cout << "red\n";?? break; ??? case Color::green: std::cout << "green\n"; break; ??? case Color::blue : std::cout << "blue\n";? break; } // int n = r; // 错误:不存在从有作用域枚举到 int 的转换 int n = static_cast<int>(r); // OK, n = 21 enum byte : unsigned char {}; // byte 是新的整数类型 byte b { 42 }; // C++17 起 OK(直接列表初始化) (3)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 } |
? | ? | |