复制初始化和显式构造函数 - 编译器差异

Cho*_*ett 4 c++ gcc constructor visual-c++

我发现Microsoft Visual C++编译器和gcc-4.8.1(由ideone.com提供)之间存在差异.考虑以下SSCCE:

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 &)
}
Run Code Online (Sandbox Code Playgroud)

我理解为什么行B b2(s);失败 - explicit构造函数匹配所以它尝试了; 但t.y不存在.精细.

但我无法弄清楚MSVC++是否正确允许B b1 = s;,或者gcc是否正确拒绝它.MSVC++正在构建一个临时的A::A(const S&),并使用它来初始化b1via B::B(const A&); 我不确定为什么gcc错误.

哪个编译器对吗?

(作为后注,如果我删除explicit两个编译器拒绝B b1 = s;- 大概是因为模板化的构造函数现在是隐式构造的公平游戏.)

编辑:从评论中看来,MSVC++似乎也拒绝了B b1 = s;Visual Studio 2012中的这一行,因此共识似乎确实是一个错误.在哪种情况下 - 错误的本质是什么?该错误消息的含义是什么?

小智 5

答案被盗,标准说:

12.3转换[class.conv]

4最多只有一个用户定义的转换(构造函数或转换函数)隐式应用于单个值.

你试图执行两个一步,S需要转换为B接受一个的构造函数,A然后另一个A构造函数接受一个S.解决方案是首先投入SA:

B b1 = static_cast<A>(s);
Run Code Online (Sandbox Code Playgroud)