在 C++14 之前,这种情况是格式错误的,并且除了一些例外之外的更一般的情况也是格式错误的。这涵盖在缺陷报告 1512:指针比较与资格转换 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1512,其中说:
根据5.9 [expr.rel]第2段,描述指针
比较,
对指针操作数(或对
一个指针操作数和一个空指针常量,或者两个空指针
常数,至少其中一个是非整数)使它们
它们的复合指针类型。
这似乎会使以下示例格式不正确,
bool foo(int** x, const int** y) {
return x < y; // valid ?
}
因为 int** 无法转换为 const int**,根据
4.4 [conv.qual] 第 4 段的规则。这对于
指针比较,当前的实现接受该示例。
缺陷报告指出,虽然这是不正确的,但实现接受了这种比较。这铿锵提交 http://llvm.org/klaus/clang/commit/b2cb1cbd727469e1567a6f2535895e6b64e12c35/表示它被视为扩展并表示两者gcc
and EDG
也把这个当做扩展,想必Visual Studio也是如此。
标准中解决了这个问题N3624:核心问题 1512:指针比较与限定转换 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3624.html,其中说:
本文提出了对工作草案必要的修改
解决核心问题 583 和 1512。特别是,它使得
[...]
and
void g(int **p1, const int**p2)
{
if (p1 == p2) { ... }
}
结构良好。
另请注意,在会议被接受 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3622.pdf有人指出,这只是将现有做法编入法典。
在该标准的其他更改中,本段被添加到本节的末尾5
[expr],其中包括新术语CV组合型:
T1和T2两种类型的cv组合型是与T1类似的T3类型
其简历资格签名 (4.4) 为:
- 对于每个 j > 0,cv3,j 是 cv1,j 和 cv2,j 的并集;
- 如果生成的 cv3,j 与 cv1,j 或 cv2,j 不同,则将 const 添加到每个 cv3,k (0
[注:给定类似类型 T1
和T2,这种结构确保两者都可以转换为T3。
--尾注] 两个操作数p1和p2的复合指针类型
分别具有类型 T1 和 T2,其中至少一个是指针
或指向成员类型或 std::nullptr_t 的指针是:
- 如果 p1 和 p2 都是空指针常量,则 std::nullptr_t;
- 如果 p1 或 p2 是空指针常量,则分别为 T2 或 T1;
- 如果 T1 或 T2 是“指向 cv1 void 的指针”,另一种类型是“指向 cv2 T 的指针”、“指向 cv12 void 的指针”,其中 cv12 是 cv1 和 cv1 的并集
简历2;
- 如果 T1 是“指向 cv1 C1 的指针”,T2 是“指向 cv2 C2 的指针”,其中 C1 与 C2 引用相关,或者 C2 与 C1 引用相关(8.5.3),
T1 和 T2 的 cv 组合型或 T2 和 T2 的 cv 组合型
分别为T1;
- 如果 T1 是“指向 cv1 U1 类型的 C1 成员的指针”并且 T2 是“指向 cv2 U2 类型的 C2 成员的指针”,其中 C1 与 C2 引用相关或
C2 与 C1 (8.5.3) 相关,是 T2 的 cv 组合类型和
T1或T1和T2的cv组合型;
- 如果T1和T2是类似的多级混合指针和指向成员类型的指针(4.4),则T1和T2的cv组合类型;
- 否则,需要确定复合指针类型的程序是格式错误的。
[ 例子:
typedef void *p;
typedef const int *q;
typedef int **pi;
typedef const int **pci;
p和q的复合指针类型是“指向const void的指针”;这
pi 和 pci 的复合指针类型是“指向 const 指针的指针”
常量整数”。 —结束示例]