Sha*_*our 34 c++ language-lawyer c++11 c++14
鉴于以下功能:
void g(int **p1, const int**p2)
{
if (p1 == p2) { }
}
Run Code Online (Sandbox Code Playgroud)
clang(返回3.0版)产生此警告(请参见实时):
warning: comparison of distinct pointer types ('int **' and 'const int **')
uses non-standard composite pointer type 'const int *const *'
[-Wcompare-distinct-pointer-types]
if (p1 == p2) { }
~~ ^ ~~
Run Code Online (Sandbox Code Playgroud)
使用-pedantic-errors标志会将其变为错误.根据标准,两者gcc(回到4.3.6)和Visual Studio(2013)都没有产生警告,是比较:
p1 == p2
Run Code Online (Sandbox Code Playgroud)
结构良好?
更一般地说,如果两个多级指针的cv资格不同于第一级,那么通过等式运算符或关系运算符进行比较是否良好?
Sha*_*our 24
在C++ 14之前,这个案例是形成不良的,一般情况下有一些例外情况也是不正确的.缺陷报告1512中包含这一点:指针比较与资格转换,其中说:
根据5.9 [expr.rel]第2段,描述指针比较,
指针操作数(或指针操作数和空指针常量,或两个空指针常量,至少其中一个)执行指针转换(4.10 [conv.ptr])和限定转换(4.4 [conv.qual])是非整数的)将它们带到它们的复合指针类型.
这似乎使以下示例格式错误,
Run Code Online (Sandbox Code Playgroud)bool foo(int** x, const int** y) { return x < y; // valid ? }因为int**不能转换为const int**,根据4.4 [conv.qual]第4段的规则.这对于指针比较来说似乎太严格了,而且当前的实现接受了这个例子.
缺陷报告指出虽然这是不正确的,但实施接受了这种比较.这个clang提交表明它被视为一个扩展并指示两者gcc并且EDG也将其视为扩展,可能这也是Visual Studio的情况.
N3624标准解决了这个问题:核心问题1512:指针比较与资格转换,其中说:
本文介绍了解决核心问题583和1512所需的工作草案的修改.特别是,它提出了这一点
[...]
和
Run Code Online (Sandbox Code Playgroud)void g(int **p1, const int**p2) { if (p1 == p2) { ... } }良好的.
还要注意到在会议上被接受的是,有人指出这只是编纂了现有做法.
在对标准的其他更改中,此段落已添加到5 [expr]部分的末尾,其中包括新术语cv-combined类型:
两种类型T1和T2的cv组合类型是类似于T1的类型T3,其cv资格特征(4.4)是:
- 对于每个j> 0,cv3,j是cv1,j和cv2,j的并集;
- 如果得到的cv3,j不同于cv1,j或cv2,j,那么const被加到每个cv3,k为0 <k <j.
[注意:给定类似的T1和T2类型,这种结构可确保两者都可以转换为T3.-end note]分别具有类型T1和T2的两个操作数p1和p2的复合指针类型,其中至少一个是指向成员类型或std :: nullptr_t的指针或指针,是:
- 如果p1和p2都是空指针常量,则std :: nullptr_t;
- 如果p1或p2分别是空指针常量,T2或T1;
- 如果T1或T2是"指向cv1 void的指针"而另一种类型是"指向cv2 T的指针","指向cv12 void的指针",其中cv12是cv1和cv2的并集;
- 如果T1是"指向cv1 C1的指针"而T2是"指向cv2 C2的指针",其中C1是与C2相关的参考或C2是与C1(8.5.3)的参考相关,cv组合类型的T1和T2或分别为T2和T1的cv组合类型;
- 如果T1是"指向cv1 U1类型C1的成员的指针"而T2是"指向cv2 U2类型C2的成员的指针",其中C1是与C2或C2相关的参考,则与C1相关(8.5.3), tv组合型T2和T1或cv组合型T1和T2;
- 如果T1和T2是类似的多级混合指针和指向成员类型的指针(4.4),那么cv-combined类型的T1和T2;
- 否则,需要确定复合指针类型的程序是不正确的.
[例如:
Run Code Online (Sandbox Code Playgroud)typedef void *p; typedef const int *q; typedef int **pi; typedef const int **pci;p和q的复合指针类型是"指向const void的指针"; pi和pci的复合指针类型是"指向const int的const指针". - 末端的例子]