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);
}
所以我们有两个重载决策候选者。对于第一个重载,第一个参数完全匹配,第二个参数需要整数转换(unsigned to signed)。对于第二个重载,第二个参数完全匹配,第一个参数需要cv-adjustment(因为&b
是指向非const的指针)。
现在,这似乎应该是完全明确的。对于重载1,第一个参数是"完全匹配"如标准关于重载决策的部分所定义,但第二部分是"转换"。对于Overload 2,两个参数都是" Exact Matches" (资格转换与身份相同)。因此(我显然不完美的推理),应该选择Overload 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? (或两者兼而有之?)我的理由是关于重载分辨率的声音吗?
答案 0 :(得分: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),并且类型T1的cv资格特征签名是T2类型的cv资格特征的适当子集。 [...]
当然,unsigned int => unsigned int
优于unsigned int => signed int
。所以在两个重载中,一个在第一个参数上有一个更好的隐式转换序列,另一个在第二个参数上有一个更好的隐式转换序列。因此,无法根据over.match.best/1区分它们。