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

Posted

技术标签:

【中文标题】逐字段构造函数生成的规则是啥?【英文标题】:What are the rules of field-by-field constructor generation?逐字段构造函数生成的规则是什么? 【发布时间】:2016-11-01 03:41:30 【问题描述】:

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

确切地说,考虑以下代码:

class S

    public:
        int a;
;
...
int a;
S s a ;

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

class S

    public:
        int a = 0;
;
...
int a;
S s a ;

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

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

【问题讨论】:

【参考方案1】:

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

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

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

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

【讨论】:

【参考方案2】:

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


C++11 中:

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

聚合是以下类型之一:

数组类型

具有

的类类型(通常是结构或联合) 没有私有或受保护的非静态数据成员 没有用户提供的构造函数,包括那些从公共基类继承的构造函数(C++17 起)(允许显式默认或删除的构造函数)(C++11 起) 没有虚拟、私有或受保护(C++17 起)基类 没有虚拟成员函数 没有默认成员初始化器(从 C++11 开始,直到 C++14

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

【讨论】:

【参考方案3】:

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

$ cat t.C
class S

public:
  int a = 0;
;


void foo()

    int a=4;

    S sa;

$ 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.

【讨论】:

非常感谢。我用的是 MSVC++ 2013,这就是问题所在。 这个问题被标记为c++11,但这并不能解释为什么版本很重要。

以上是关于逐字段构造函数生成的规则是啥?的主要内容,如果未能解决你的问题,请参考以下文章

构造函数

构造函数生成规则

如何使用 Visual Studio(和/或 ReSharper)从类字段生成构造函数?

string类精简版

java中构造方法和拷贝构造方法是啥意思

explicit 构造函数