【问题标题】:Why do I get error C2797 in this example?为什么在此示例中出现错误 C2797?
【发布时间】:2014-10-25 22:35:01
【问题描述】:

我有以下代码:

struct X
{
    int a, b;
};

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

private:
    X x_;
};

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

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

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

【问题讨论】:

  • 是的。如果您暗示答案就在那里,我不明白,如果您能在此处的答案中指出,我将不胜感激。
  • @Dan:您正在使用列表初始化{},并在成员初始化列表中这样做。错误消息说这是合法的事情,但编译器还没有准备好让你这样做。尝试x_(x) 作为解决方法,这是直接初始化,而不是列表初始化。
  • @Ben:所以如果我理解正确,你是说{} 初始化是合法的,但它只是没有在这个编译器中实现?
  • @Dan:是的。更有可能的是,在这种特殊情况下决定它是否合法的编译器部分也尚未实现。由于您的 struct X 是一个聚合,我将使用大括号 {} 进行聚合初始化(一种特殊形式的列表初始化),并使用 () 进行复制构造,这就是您在这里所拥有的。
  • @Ben:谢谢。请将此表述为一个简短的答案。

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


【解决方案1】:

来自标准:

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

[...]

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

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

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

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

【讨论】:

    【解决方案2】:

    正如您所说,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 以外的人都不知道)。你的代码被送到工厂,装载到传送带上,开始沿着装配线移动,然后……从传送带的末端掉下来,因为处理这种代码的机器还没有在工厂里.没有人知道如果机器在那里捡起它,它会不会把它丢在错误堆里,或者把它拿到另一个传送带上。

    【讨论】:

    • 我想我不清楚的是:x_{x} 不是列表初始化,是吗?根据统一的初始化规则,这个语法应该是调用X的(编译器定义的)拷贝构造函数,即X(const X&)notX(std::initializer_list)。这部分 C++ 语言语法没有被 gcc 或 MSVC 正确解析。
    • 我对我的问题进行了编辑,以阐明我正在寻找的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-04
    • 2021-09-03
    • 1970-01-01
    • 2017-11-20
    • 1970-01-01
    • 2018-05-16
    • 2020-01-30
    相关资源
    最近更新 更多