逐字段构造函数的生成规则是什么?

What are the rules of field-by-field constructor generation?

我发现 class 使用初始化列表语法的可能性取决于 class 字段是否具有默认值。为什么?

准确地说,请考虑以下代码:

class S
{
    public:
        int a;
};
...
int a;
S s{ a };

它编译没有任何问题。但是,如果我将默认值添加到 class 字段,它将停止构建:

class S
{
    public:
        int a = 0;
};
...
int a;
S s{ a };

Error 1 error C2440: 'initializing' : cannot convert from 'initializer-list' to 'S'

为什么?还有什么影响这样的构造函数生成?

所示代码在 gcc 6.1.1 下编译时没有任何问题。您可能正在使用不完全支持 C++14 的旧编译器:

$ cat t.C
class S
{
public:
  int a = 0;
};


void foo()
{
    int a=4;

    S s{a};
}
$ g++ -std=c++1z -g -c -o t.o t.C
$ g++ --version
g++ (GCC) 6.1.1 20160510 (Red Hat 6.1.1-2)
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

C++14 中,您的代码是有效的,应该可以使用任何 C++14 兼容的编译器进行编译。


C++11 然而:

如果你没有a的默认值,你的类型是聚合,因此aggregate initialization可以执行:

An aggregate is one of the following types:

  • array type

  • class type (typically, struct or union), that has

    • no private or protected non-static data members
    • no user-provided constructors , including those inherited from public bases (since C++17) (explicitly defaulted or deleted constructors are allowed) (since C++11)
    • no virtual, private, or protected (since C++17) base classes
    • no virtual member functions
    • no default member initializers (since C++11, until C++14)

一旦为属性 a 添加了默认值,就无法再执行聚合初始化,因为您的类型不再是聚合。

在这两种情况下,S 的默认构造函数都没有参数。 class 的形式不影响默认构造函数的生成。此外,没有隐式生成的构造函数采用 int.

如果 S 是一个 聚合 ,那么使用 S s = { arguments_opt }; 不会调用 S 的构造函数。相反,它会调用称为 聚合初始化 的东西。聚合是唯一 class 可以在不调用构造函数的情况下创建 class 的对象。

仅当 S 不是 聚合时,S s = { arguments_opt }; 才会尝试将参数列表与 [=10= 的构造函数的参数相匹配].

(正如其他人所解释的,在 C++11 中,为非静态数据成员提供 brace-or-equal-initializer 使得 class不是聚合)。