2

我有以下代码:

struct X
{
    int a, b;
};

class Y
{
public:
    Y(const X& x) : x_{x} {};  // C2797 error

private:
    X x_;
};

使用 MSVC2013 更新 3 编译,它抱怨C2797 错误。如果我用括号(即x_(x))替换花括号,程序编译成功。

为什么会这样?此编译器行为是否符合 C++11?那么 C++14 呢?

编辑:为了更清楚,我不确定x_{x}上面是否应该根据标准 callX(std::initializer_list)或者它是否是 call 的有效语法X(const X&)。据我所知,是后者。我对吗?

4

2 回答 2

2

从标准:

— 如果 T 是聚合,则执行聚合初始化。

[...]

— 否则,如果 T 是类类型,则考虑构造函数。枚举适用的构造函数,并通过重载决议(13.3、13.3.1.7)选择最佳构造函数。如果需要缩小转换(见下文)来转换任何参数,则程序格式错误。

在上面的上下文中,x_{x}不会调用复制构造函数,因为X是一个聚合。它将尝试聚合初始化,其中:

  • 在 MSVC 中,未实现。XMSVC 在is时似乎也无法编译std::string,这不是聚合,因此它可能存在一些 C++11 合规性问题。

  • 在 gcc 中,它已实现,但程序格式错误且无法编译(尝试初始化期望{int, int}来自{const X}.

于 2014-10-26T10:18:18.520 回答
1

如您所述,gcc确实知道该语法的含义,并给出了特定的错误消息:

cannot convert ‘const X’ to ‘int’ in initialization

这是因为花括号{}触发列表初始化和聚合类型的列表初始化(你struct X是一个聚合,如果你不知道为什么,只是想“像一个数组,它只是包含没有任何行为的东西”)执行聚合初始化。聚合初始化意味着初始化器按顺序与数据成员配对,并且任何额外的数据成员都会初始化值。

x_.ax x_.b配对 与无配对,因此值已初始化

这不是你想要的,因为你不能完全x投入x_.a(这是 gcc 告诉你的)。您想要的是使用复制构造函数直接初始化,写为_x(x).

Visual C++ 中的故事有点不同。Microsoft 工程师仍在努力添加 C++11 支持,这是他们尚未完成的事情之一(至少在您的版本中)。编译器知道当它{}在 ctor 初始化器列表中看到时,这意味着列表初始化,但它不知道如何做到这一点,所以它放弃了。

特别是,它没有达到X将初始化程序与数据成员配对,并找出是否可以配对x_.ax程度。

当编译器告诉你“这没有实现”时,这并不意味着代码是好的,也不意味着代码是坏的。这意味着编译代码需要尚未发布的逻辑(可能尚未编写,可能尚未测试,Microsoft 以外的人都不知道)。你的代码被送到工厂,装载在传送带上,开始沿着装配线移动,然后……从传送带的末端掉下来,因为处理这种代码的机器还没有在工厂里. 没有人知道如果机器在那里捡起它,它会不会把它丢在错误堆里,或者把它放在另一个传送带上。

于 2014-10-25T23:38:36.407 回答