VC ++ 2012中出现意外模糊的重载决策

时间:2014-09-02 13:13:40

标签: c++ visual-c++ overloading overload-resolution compiler-bug

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? (或两者兼而有之?)我的理由是关于重载分辨率的声音吗?

1 个答案:

答案 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区分它们。