在C++14之前,这种情况是不规范的,更一般的带有一些例外情况也是不规范的。这在
缺陷报告1512:指针比较与限定转换中有所涵盖,其中提到:
According to 5.9 [expr.rel] paragraph 2, describing pointer
comparisons,
Pointer conversions (4.10 [conv.ptr]) and qualification conversions (4.4 [conv.qual]) are performed on pointer operands (or on
a pointer operand and a null pointer constant, or on two null pointer
constants, at least one of which is non-integral) to bring them to
their composite pointer type.
This would appear to make the following example ill-formed,
bool foo(int** x, const int** y) {
return x < y; // valid ?
}
because int** cannot be converted to const int**, according to the
rules of 4.4 [conv.qual] paragraph 4. This seems too strict for
pointer comparison, and current implementations accept the example.
这份缺陷报告指出,尽管它格式不正确,但实现仍接受这样的比较。这个
clang commit表明它被视为扩展,并且表明
gcc
和
EDG
也将其视为扩展,据推测Visual Studio也是如此。
这在标准中已得到解决,
N3624: Core Issue 1512: Pointer comparison vs qualification conversions提到:
This paper presents the modifications to the Working Draft necessary
to resolve core issues 583 and 1512. In particular, it makes
[...]
and
void g(int **p1, const int**p2)
{
if (p1 == p2) { ... }
}
well-formed.
请注意,在
会议中已经接受的情况下,已经注意到这只是将现有做法编码。
在标准的其他更改中,该段落被添加到第
5
节的结尾
[expr],其中包括新术语
cv-combined type。
The cv-combined type of two types T1 and T2 is a type T3 similar to T1
whose cv-qualification signature (4.4) is:
- for every j > 0, cv3,j is the union of cv1,j and cv2,j ;
- if the resulting cv3,j is different from cv1,j or cv2,j , then const is added to every cv3,k for 0 < k < j.
[ Note: Given similar types T1
and T2, this construction ensures that both can be converted to T3.
—end note ] The composite pointer type of two operands p1 and p2
having types T1 and T2, respectively, where at least one is a pointer
or pointer to member type or std::nullptr_t, is:
- if both p1 and p2 are null pointer constants, std::nullptr_t;
- if either p1 or p2 is a null pointer constant, T2 or T1, respectively;
- if T1 or T2 is “pointer to cv1 void” and the other type is “pointer to cv2 T”, “pointer to cv12 void”, where cv12 is the union of cv1 and
cv2 ;
- if T1 is “pointer to cv1 C1” and T2 is “pointer to cv2 C2”, where C1 is reference-related to C2 or C2 is reference-related to C1 (8.5.3),
the cv-combined type of T1 and T2 or the cv-combined type of T2 and
T1, respectively;
- if T1 is “pointer to member of C1 of type cv1 U1” and T2 is “pointer to member of C2 of type cv2 U2” where C1 is reference-related to C2 or
C2 is reference-related to C1 (8.5.3), the cv-combined type of T2 and
T1 or the cv-combined type of T1 and T2, respectively;
- if T1 and T2 are similar multi-level mixed pointer and pointer to member types (4.4), the cv-combined type of T1 and T2;
- otherwise, a program that necessitates the determination of a composite pointer type is ill-formed.
[ Example:
typedef void *p;
typedef const int *q;
typedef int **pi;
typedef const int **pci;
The composite pointer type of p and q is “pointer to const void”; the
composite pointer type of pi and pci is “pointer to const pointer to
const int”. —end example ]