我发现Microsoft Visual C++编译器和gcc-4.8.1(由ideone.com提供)之间存在差异
struct S
{
int x;
};
class A
{
public:
int x;
A(const S& s) : x(s.x) {}
};
class B
{
int x, y;
public:
template <typename T> explicit B(const T& t) : x(t.x), y(t.y) {}
B(const A& a) : x(a.x), y(0) {}
};
int main() {
S s = {1};
B b1 = s; // Compiles OK on MSVC++;
// Fails on gcc - conversion from ‘S’ to non-scalar type ‘B’ requested
B b2(s); // Fails on both - Error: y is not a member of S in B::B<S>(const T &)
}
我理解B b2(s);
行失败的原因——explicit
构造函数匹配,所以尝试过;但CCD_ 3不存在。好的
但我不知道MSVC++允许B b1 = s;
是否正确,或者gcc拒绝它是否正确。MSVC++正在从A::A(const S&)
构建一个临时,并用它通过B::B(const A&)
初始化b1
;我不知道为什么gcc会出错。
哪个编译器是对的?
(如后所述,如果我删除explicit
,两个编译器都会拒绝B b1 = s;
——可能是因为模板化构造函数现在对临时的隐式构造来说是公平的。)
编辑:从评论来看,MSVC++似乎也拒绝了Visual Studio 2012中的B b1 = s;
行,所以一致认为这确实是一个错误。在哪种情况下,错误的性质是什么?错误消息是什么意思?
从这个答案中窃取,标准说:
12.3转换[class.conv]
4最多一个用户定义的转换(构造函数或转换函数)隐式应用于单个值。
您正尝试在一个步骤中执行两个步骤,S
需要转换为接受A
的B
的构造函数,然后再转换另一个A
的接受S
的构造函数。解决方案是首先将S
转换为A
:
B b1 = static_cast<A>(s);