【问题标题】:Copy-initialisation and explicit constructor - compiler discrepancy复制初始化和显式构造函数 - 编译器差异
【发布时间】:2014-01-09 10:31:33
【问题描述】:

我发现 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 &)
}

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

但我无法确定 MSVC++ 是否正确允许B b1 = s;,或者 gcc 是否正确拒绝它。 MSVC++ 正在从A::A(const S&amp;) 构造一个临时对象,并使用它通过B::B(const A&amp;) 初始化b1;我不确定为什么 gcc 错误。

哪个编译器是对的?

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

编辑: 从 cmets 看来,MSVC++ 似乎也拒绝了 Visual Studio 2012 中的 B b1 = s; 行,因此大家一致认为这确实是一个错误。在这种情况下 - 错误的性质是什么?那条错误消息是什么意思

【问题讨论】:

  • VS2012 也因B b1 = s; 而失败。我相信失败是正确的行动。哪个 VS 没有失败?
  • 有趣。我的版本是 VS2010,所以它可能是一个固定的错误(升级时可能会破坏我们的代码!)。不过,我仍然很想知道发生了什么。
  • @egur - 2012 年的错误信息是什么?
  • 这是一个错误,因为从 S 构造 B 需要连续两次用户定义的转换 (S -> A -> B),而只允许一次。 VS2010 可能允许它。
  • @Simple 我发布了一个答案,如果我对任何细节有误,请随时纠正我。

标签: c++ visual-c++ gcc constructor


【解决方案1】:

从这个answer偷来的,标准说:

12.3 转换 [class.conv]

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

您试图一步执行两个,S 需要转换为接受AB 的构造函数,然后另一个用于接受@ 的A 的构造函数987654326@。解决方案是首先将S 转换为A

B b1 = static_cast<A>(s);

【讨论】:

  • 这显然是正确的;但是您可能会争辩说S -&gt; A 是一个临时的,然后A -&gt; B 是复制初始化,每个用户定义的转换都应用于不同的对象。另外,conversion from ‘S’ to non-scalar type ‘B’ requested 想告诉我什么?
  • @Chowlett 结构/类是非标量类型。我认为错误信息令人困惑。
  • MSVC 接受两步转换作为语言扩展。如果要禁用 MS 语言扩展,请使用 /Za 标志进行编译。当您这样做时,编译器将拒绝该示例。
猜你喜欢
  • 2015-10-24
  • 1970-01-01
  • 2017-09-04
  • 1970-01-01
  • 1970-01-01
  • 2015-06-10
  • 1970-01-01
  • 2012-08-16
  • 1970-01-01
相关资源
最近更新 更多