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

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

本文关键字:规则 是什么 字段 构造函数      更新时间:2023-10-16

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

更准确地说,考虑下面的代码:

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

编译时没有任何问题。但是如果我给class字段添加一个默认值,它就会停止构建:

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

错误1错误C2440: 'initializing':无法从'initializer-list'转换为'S'

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

c++ 14中,你的代码是有效的,可以用任何c++ 14兼容的编译器编译。


c++ 11然而:

如果您没有a的默认值,则您的类型是聚合,因此可以执行聚合初始化:

聚合是下列类型之一:

    数据类型
  • 类类型(通常是struct或union),具有

    • 没有私有或受保护的非静态数据成员
    • 没有用户提供的构造函数,包括从公共基继承的构造函数(自c++ 17起)(允许显式默认或删除构造函数)(自c++ 11起)
    • 没有虚的、私有的或受保护的(c++ 17起)基类
    • 没有虚成员函数
    • 没有默认的成员初始化式(从c++ 11开始,直到c++ 14)

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

显示的代码在编译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.

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

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

只有当S而不是聚合时,S s = { arguments_opt };才尝试将实参列表与S的构造函数的形参进行匹配。

(正如其他人所解释的,在c++ 11中,为非静态数据成员提供大括号或等号初始化式使类不是聚合)。