language/implicit_conversion 限定性类型转换
写在前面
内容见 implicit conversion。
限定性转换指的是和 cv 属性有关的类型转换,它的发生必须满足一定的条件。
相似类型
忽略掉各层的 cv 属性,如果两个类型形式相同,就是相似类型。比如 const int* volatile *
和 int** const
。
Important
函数指针对应函数的参数和返回值类型的 cv 属性不可以忽略。可见原页面的例子,这里略去。
限定性分解
合并限定性和类型转换规则
规则说明
- C++20 之前
T1
到T2
的类型转换规则和限定性组合类型是分开定义的,而 C++20 之后类型转换规则是借由限定性组合类型定义的。 - 限定性组合类型的两个参数类型是有顺序的,
A
和B
的限定性组合类型、B
和A
的限定性组合类型是两码事。 - C++20 中,限定性组合类型的定义改变了,但是类型转换的规则没有变:
- 要求限定性组合类型是无 cv 限定的
T2
,说明这个类型和T2
相似,同时它又必须和T1
相似(第一排),所以 C++20 之前T1
和T2
相似的要求没有变。 - “
cv3_i
是cv1_i
和cv2_i
的并集” 是对 “对于每个非零i
,如果cv1_i
中有const
,……”的转述。 - 限定性组合类型新增的对于
Pj_i
的描述不会影响类型转换的判断,因为T1
和T2
必须相似,所以对于固定的i
,Pj_i
($j=1, 2, 3$)必须相同。
- 要求限定性组合类型是无 cv 限定的
C 和 C++ 的不同之处
char** p = 0;
char * const* p1 = p; // C 与 C++ 中 OK
const char* const * p2 = p; // C 中错误,C++ 中 OK
Note
即便是在 C++ 中加上 extern "C"
,依然是用 C++ 的语法检查,而不会用 C 的语法检查。另外,在这个问题上,C 语言编译器虽然认为有错误,但是依然可能会继续编译,比如 gcc 只是会给出不兼容类型转换的警告。
简单地说明转换规则
定义 1:将靠近变量名的一侧称为内层,最内层、0 层都是指这一层,而向外层数逐渐增大。
定义 2:对于两个相似类型 T1
和 T2
,T1
比 T2
在某一层更严格指的是 T1
在 T2
某一层 cv 限定符的基础上,增加了 const
或者 volatile
属性。
想要 T1
转换成 T2
:
- 两者必须相似。
- 忽略 0 层的 cv 限定符,
T2
每一层的类型要相同严格、或者更严格。 - 从最外层起到第 1 层(包含),令
T2
第一个更严格的层为j
,需要j
不存在、或者[i, j)
中都有const
属性(在 C++ 中) /j
为 1(在 C 中)。
代码例子:
void f() {
char ** const p = nullptr;
char volatile * const *p1 = p;
// char volatile **p2 = p;
// 第 2 层有了 volatile,所以 [1, 2) 层(也就是第 1 层)需要加 const
}