我有一小段C++11代码,g++(4.7或4.8)拒绝编译并声称B2 b2a(x,{P(y)})的构造函数调用是模棱两可的。 Clang ++对该代码感到满意,但拒绝编译B2 b2b(x,{{P(y)}}),而g ++可以完美地编译它! 两个编译器都可以接受以{...}或{{...}}作为参数的B1构造函数。任何C ++语言专家都可以解释哪个编译器是正确的(如果有的话)以及发生了什么。下面是代码:
#include <initializer_list>
using namespace std;
class Y {};
class X;
template<class T> class P {
public:
P(T);
};
template<class T> class A {
public:
A(initializer_list<T>);
};
class B1 {
public:
B1(const X&, const Y &);
B1(const X&, const A<Y> &);
};
class B2 {
public:
B2(const X &, const P<Y> &);
B2(const X &, const A<P<Y>> &);
};
int f(const X &x, const Y y) {
B1 b1a(x, {y});
B1 b1b(x, {{y}});
B2 b2a(x, {P<Y>(y)});
B2 b2b(x, {{P<Y>(y)}});
return 0;
}
同时也有编译器错误,clang:
$ clang++ -stdlib=libc++ -std=c++11 test-initialiser-list-4.cc -o test.o -c
test-initialiser-list-4.cc:32:6: error: call to constructor of 'B2' is ambiguous
B2 b2(x, {{P<Y>(y)}});
^ ~~~~~~~~~~~~~~
test-initialiser-list-4.cc:26:5: note: candidate constructor
B2(const X &, const P<Y> &);
^
test-initialiser-list-4.cc:27:5: note: candidate constructor
B2(const X &, const A<P<Y>> &);
^
g++:
test-initialiser-list-4.cc: In function 'int f(const X&, Y)':
test-initialiser-list-4.cc:32:21: error: call of overloaded 'B2(const X&, <brace-enclosed initializer list>)' is ambiguous
B2 b2(x, {P<Y>(y)});
^
test-initialiser-list-4.cc:32:21: note: candidates are:
test-initialiser-list-4.cc:27:5: note: B2::B2(const X&, const A<P<Y> >&)
B2(const X &, const A<P<Y>> &);
^
test-initialiser-list-4.cc:26:5: note: B2::B2(const X&, const P<Y>&)
B2(const X &, const P<Y> &);
^
这似乎涉及到统一初始化、初始化列表语法和带有模板参数的函数重载之间的交互(我知道g++对此要求相当严格),但我不是足够了解标准的律师,无法理解这里应该是正确的行为!
A
和从T
创建P
应该都是精确匹配,因此存在歧义。我无法解释的是为什么编译器选择不同的内容进行投诉。 - Mark B