为什么我在这个例子中得到错误C2797?

时间:2014-10-25 22:35:02

标签: c++ c++11 visual-studio-2013 initialization uniform-initialization

我有以下代码:

struct X
{
    int a, b;
};

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

private:
    X x_;
};

使用MSVC2013 Update 3编译,它抱怨C2797 error。如果我用parantheses替换花括号(即x_(x)),程序将成功编译。

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

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

2 个答案:

答案 0 :(得分:2)

来自标准:

  

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

     

[...]

     

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

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

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

  • 在gcc中,它已实现,但该程序格式错误且无法编译(尝试初始化期望{int, int}的{​​{1}}的聚合。

答案 1 :(得分:1)

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

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

那是因为花括号{}触发列表初始化,而列表初始化为聚合类型(如果您不知道原因,则struct X是一个聚合,只是思考"就像一个数组,它只是保存没有任何行为的东西")执行聚合初始化。聚合初始化意味着初始化程序按顺序与数据成员配对,并且任何额外的数据成员都会初始化值。

x_.ax配对 x_.b与任何内容配对,因此值已初始化

这不是你想要的,因为你不能将所有x都粘贴到x_.a(这就是gcc告诉你的)。你想要的是使用拷贝构造函数直接初始化,写为_x(x)

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

特别是,它没有看到X是聚合,将初始化程序与数据成员配对,并查明是否将x_.ax配对是可能的。

当编译器告诉你"这没有实现"时,它并不意味着代码是好的,它并不意味着代码是坏的。这意味着编译代码需要尚未发布的逻辑(可能尚未编写,尚未测试,微软以外的任何人都不知道)。你的代码被运送到工厂,装在传送带上,开始向下移动装配线,然后......从带子的末端掉下来,因为处理这种代码的机器不在工厂呢。没有人知道机器是否在那里捡起它,它会将它丢弃在错误堆中或者在另一台输送机上得到它。