5

Visual C++ 2012。代码。我认为它应该编译;编译器恭敬地不同意。我已将我的复制范围缩小到:

struct  B { };

void foo(B* b, signed int si) { } // Overload 1
void foo(B const* b, unsigned int ui) { } // Overload 2

int main()
{
    B b;
    unsigned int ui;
    foo(&b, ui);
}

所以我们有两个重载解决方案的候选者。对于第一个重载,第一个参数完全匹配,第二个参数需要整数转换(无符号到有符号)。对于第二个重载,第二个参数完全匹配,第一个参数需要 cv 调整(因为&b是指向非常量的指针)。

现在看来,这应该是完全明确的。对于重载 1,第一个参数是标准的重载决议部分定义的“精确匹配”,但第二个参数是“转换”。对于重载 2,两个参数都是“精确匹配”(资格转换与身份处于同一等级)。因此(我的推理显然不完美),应该选择重载 2,没有歧义。但是:

a.cpp(12): error C2666: 'foo' : 2 overloads have similar conversions
    a.cpp(6): could be 'void foo(const B *,unsigned int)'
    a.cpp(5): or       'void foo(B *,int)'
    while trying to match the argument list '(B *, unsigned int)'
    note: qualification adjustment (const/volatile) may be causing the ambiguity

GCC 在默认方言和 C++11 中的代码似乎都很好(感谢 IDEOne!)。所以我很想把它归结为 MSVC 中的一个错误,但是(a)你知道他们对那些认为他们的错误是编译器错误的人说了什么,并且(b)这似乎是一个非常明显的错误,在一致性测试期间会发出危险信号的那种。

这是不合规的 MSVC,还是不合规的 GCC?(或两者兼而有之?)我关于过载分辨率的推理是否合理?

4

1 回答 1

7

MSVC 是正确的。

gcc 4.9.0 说:

警告:ISO C++ 说这些是模棱两可的,即使第一个的最差转换比第二个的最差转换要好:[默认启用]

clang 3.4.1 同意这两个功能是模棱两可的。

尽管B* => B*B* => B const*都具有精确匹配排名,但前者仍然是每个 over.ics.rank/3 更好的转换序列;这是(每个示例)确保:

int f(const int *);
int f(int *);
int i;
int j = f(&i); // calls f(int*)

来自 over.ics.rank/3:

标准转换序列 S1 是比标准转换序列 S2 更好的转换序列,如果 [...]
— S1 和 S2 仅在它们的限定转换上不同,并且分别产生相似的类型 T1 和 T2 (4.4),并且 cv 限定签名T1 类型是 T2 类型的 cv 限定签名的真子集。[...]

而且,当然,unsigned int => unsigned intunsigned int => signed int. 所以在这两个重载中,一个在第一个参数上具有更好的隐式转换序列,另一个在第二个参数上具有更好的隐式转换序列。因此它们无法根据 over.match.best/1 进行区分。

于 2014-09-02T13:17:00.417 回答