【发布时间】:2013-07-16 07:09:01
【问题描述】:
我有一小段 C++11 代码,g++(4.7 或 4.8)拒绝编译,声称对 B2 b2a(x, {P(y)}) 的构造函数的调用不明确。 Clang++ 对那个代码很满意,但拒绝编译 G++ 非常乐意编译的 B2 b2b(x, {{P(y)}})!
两个编译器都对使用 {...} 或 {{...}} 作为参数的 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++ 对此相当严格),但我还不够标准律师能够解开应该是什么这里的正确行为!
【问题讨论】:
-
函数“f”中两个名为“b2b”的局部变量只是一个错字,不是问题的原因,我认为......
-
在我看来,从 initializer_list 创建
A和从T创建P都应该是完全匹配的,因此会产生歧义。我无法解释的是为什么编译器会选择不同的来抱怨。 -
是的,我很高兴有一个(或两个!)选项模棱两可,但编译器不同意它应该是什么,我不知道哪个应该是正确的自己。因此要求澄清。
标签: c++ templates c++11 ambiguous constructor-overloading