16

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

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

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

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

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

错误 1 ​​错误 C2440:“正在初始化”:无法从“初始化器列表”转换为“S”

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

4

3 回答 3

19

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


然而,在C++11中:

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

聚合是以下类型之一:

  • 数组类型

  • 类类型(通常是结构或联合),具有

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

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

于 2016-06-29T12:28:50.403 回答
4

显示的代码在 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.
于 2016-06-29T12:28:18.163 回答
2

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

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

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

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

于 2016-06-30T09:25:07.030 回答