cv-qualifier
cv-qualifier-seq
词法上,C++ 标准用 BNF 产生式描述了 cv-qualifier-seq 的词法 :TODO: §9.3/5
cv-qualifier-seq:
cv-qualifier cv-qualifier-seq_opt
cv-qualifier:
const
volatile
BNF 产生式在词法上简洁明了精确,但若用自然语言表述即:cv 限定符序列是一个非空的 cv 限定符的序列,而一个 cv 限定符要么是 const 要么是 qulified 。
语法上,C++ 标准规定了每个 cv-qualifier 在一个 cv-qualifier-seq 中至多出现一次。TODO: §9.2.8.1/1
cv-qualifier
const
const 对象
一个对象若被声明为 const :
- 它的非
mutable子对象也是const的。const是子对象传播的,mutable可以打断子对象传播。
- 直接修改对象的表达式不合法。
S = ?是直接修改对象,S.x = ?不是直接修改对象,这里的.表示在修改子对象。
const 在类中的可观察影响
一个类如果包含 const 限定的非类类型静态数据成员,默认拷贝/移动赋值运算符被隐式删除。
volatile
特性比较多,核心作用归纳起来就是,volatile 限定用于处理程序无法预测的行为,并限制编译器优化。
典型的比如硬件信号是一种程序自身无法预测的行为,一个信号量如果不 volatile 限定,可能被编译器省略、合并,或者交换另一个信号量的位置。如果真的这么做了结果是比较灾难性的,硬件完全无法和程序正常沟通,C++ 通常用 volatile 处理信号量这种比较基础的硬件和程序间的交互依赖。
cv-qualified
cv-qualified 顾名思义上即被被 cv-qualifier 限定。
cv-qualified type
cv-qualified type 指被 const-qualified、volatile-qualified、const volatile-qualified 的 type 。cv-unqualified 即未被 cv-qualifed 。
每一个 cv-unqualifed 的对象类型和 void 类型,都有三个对应的 cv-qualified 版本。这四种类型变体是不同类型,它们会影响重载协议,但具有相同的二进制表示和对齐要求。
除数组外,其他的复合类型不因其组成类型的 cv-qualifier 而被 cv-qualified 。一个数组的元素是 cv-qualified 的,则该数组类型被认为是相同的 cv-qualfiled 的。[1]§6.8.3/3
函数类型永远不会被 cv-qualified 。[1]§7.3.5/5
cv限定符可以出现在非静态成员函数上。实际上限定的是该函数内的纯右值this。
cv-qualified 的引用是不合法的,除非引用的 cv-qualifier 是被 typedef-name 或 decltype-specifier 引入的,但此时的 cv-qualifier 实际上会被忽略。[1]§9.3.3.2/1
cv-qualified 的偏序
cv-unqualified < 单 cv-qualified ,单 cv-qualified < 双 cv-qualified 。
对于单层指针,类型为“指向 cv_1 T 的指针”的纯右值可以转换为类型“指向 cv_2 T 的指针”的纯右值,如果“cv_2 T”比“cv_1 T”更 cv 限定。
对于多层指针,限定转换则需要参考限定转换的严格要求。
longest cv-decomposition
类型 T 的一个最长 cv 分解是一个由 cv_i 和 P_i 组成的序列,使得 T 是 cv_0 P_0 cv_1 P_1 \cdots cv_{n - 1} P_{n = 1} cv_n U ,其中:
- \(n \geq 0\) 且最长;
cv_i是一组cv-qualifiers;P_i是pointer to:指针构造——把后续类型作为被指向类型,构造出指针类型。pointer to member of class C_i of type:指向类C_i的成员指针构造——把后续类型作为该成员的类型,构造成员指针类型。arrary of N_i:数组构造——把后续类型作为元素类型,构造出N_i个元素的数组类型。arrary of unknow bound of:未知边界数组构造——把后续类型作为元素类型,构造出未知边界的元素个数的数组类型。
U是剥离所有P_i后的最内层/底层类型。
top-level cv-qualifiers
一个 T 的最长 cv 分解若是 cv_0 P_0 cv_1 P_1 \cdots cv_{n - 1} P_{n = 1} cv_n U ,则它的顶层 cv 限定符是 cv_0 。
顶层 cv 限定符描述的是对象自身的限定,引用和函数没有顶层 cv 限定符。
这里关于 const 限定有一个常见的例子,在一个 pointer to 表达式中,如果存在 const 限定:
- 顶层
const限定的是对象本身,对象不可通过表达式修改。 - 非顶层
const限定的是pointer to本身,pointer to不可通过表达式修改。
cv-qualification signature
一个 T 的最长 cv 分解若是 cv_0 P_0 cv_1 P_1 \cdots cv_{n - 1} P_{n = 1} cv_n U ,则它的 cv 限定签名是 cv_1, cv_2, \cdots, cv_n 。
similar types
两个类型 T_1 和 T_2 是相似类型,若它们的最长 cv 分解长度一样且对应 P_i 和 U 相同。
qualification conversion
类型 T_1 的纯右值可以转换为类型 T_2 ,若满足:
cv_{ij}为类型T_j的cv限定签名中的cv-qualifier。T_1和T_2是相似类型。- \(cv_{i1} \neq cv_{i2} \Rightarrow \forall 0 < k < i. \text{const} \in cv_{k2}\) 。
[1] ISO/IEC. Working Draft, Standard for Programming Language C++: N4861[EB/OL]. (2020-04-01)[2026-09-22]. https://timsong-cpp.github.io/cppwp/n4861/. ↩
浙公网安备 33010602011771号