给定int**p1和const int**p2是p1 == p2是否形成良好?

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])是非整数的)将它们带到它们的复合指针类型.

这似乎使以下示例格式错误,

bool foo(int** x, const int** y) {
   return x < y;  // valid ?
}
Run Code Online (Sandbox Code Playgroud)

因为int**不能转换为const int**,根据4.4 [conv.qual]第4段的规则.这对于指针比较来说似乎太严格了,而且当前的实现接受了这个例子.

缺陷报告指出虽然这是不正确的,但实施接受了这种比较.这个clang提交表明它被视为一个扩展并指示两者gcc并且EDG也将其视为扩展,可能这也是Visual Studio的情况.

N3624标准解决了这个问题:核心问题1512:指针比较与资格转换,其中说:

本文介绍了解决核心问题583和1512所需的工作草案的修改.特别是,它提出了这一点

[...]

void g(int **p1, const int**p2)
{
   if (p1 == p2) { ... }
}
Run Code Online (Sandbox Code Playgroud)

良好的.

还要注意到在会议上被接受的是,有人指出这只是编纂了现有做法.

在对标准的其他更改中,此段落已添加到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;
  • 否则,需要确定复合指针类型的程序是不正确的.

[例如:

    typedef void *p;
    typedef const int *q;
    typedef int **pi;
    typedef const int **pci;
Run Code Online (Sandbox Code Playgroud)

p和q的复合指针类型是"指向const void的指针"; pi和pci的复合指针类型是"指向const int的const指针". - 末端的例子]

  • @MattMcNabb不,它不能.严格别名允许通过"与对象的动态类型相似的类型(如4.4中所定义)"进行访问.`const int*`与*int*`类似*. (2认同)
  • @immibis琐碎的答案是"如果两者都是空指针".无论如何,在`int**`和`const int**`之间转换只需要一个`const_cast`,而不是`reinterpret_cast`,我怀疑在所有常用和预期的方式中使用结果指针是有效的. (2认同)