C++ 按字段生成构造函数的规则是什么?
我发现对类使用初始值设定项列表语法的可能性取决于类字段是否具有默认值。为什么?C++ 按字段生成构造函数的规则是什么?,c++,c++11,initializer-list,aggregate-initialization,C++,C++11,Initializer List,Aggregate Initialization,我发现对类使用初始值设定项列表语法的可能性取决于类字段是否具有默认值。为什么? 确切地说,考虑下面的代码: class S { public: int a; }; ... int a; S s{ a }; 它编译起来没有任何问题。但如果我向类字段添加默认值,它将停止生成: class S { public: int a = 0; }; ... int a; S s{ a }; 错误1错误C2440:“正在初始化”:无法从“初始值设定项列表”转换
确切地说,考虑下面的代码:
class S
{
public:
int a;
};
...
int a;
S s{ a };
它编译起来没有任何问题。但如果我向类字段添加默认值,它将停止生成:
class S
{
public:
int a = 0;
};
...
int a;
S s{ a };
错误1错误C2440:“正在初始化”:无法从“初始值设定项列表”转换为“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
的默认值,则您的类型是聚合,因此可以执行以下操作:
聚合是以下类型之一:
- 数组类型
- 类类型(通常为struct或union),具有
- 没有私有或受保护的非静态数据成员
- 没有用户提供的构造函数,包括从公共基继承的构造函数(从C++17开始)(允许显式默认或删除的构造函数)(从C++11开始)
- 没有虚拟、私有或受保护(自C++17以来)基类
- 没有虚拟成员函数
- 没有默认的成员初始值设定项(从C++11开始,直到C++14)
一旦为属性
a
添加默认值,就无法再执行聚合初始化,因为您的类型不再是聚合。在这两种情况下,S
的默认构造函数都不带参数。类的形式不影响默认构造函数的生成。此外,没有隐式生成的构造函数接受int
如果S
是一个聚合,那么用法S={arguments\u opt}代码>不调用S
的构造函数。相反,它调用称为聚合初始化的东西。聚合是唯一可以在不调用构造函数的情况下创建该类的对象的类
只有当S
不是一个聚合时,S={arguments\u opt}代码>尝试将参数列表与S
的构造函数的参数相匹配
(正如其他人所解释的,在C++11中,为非静态数据成员提供大括号或相等的初始值设定项使类不是聚合)。非常感谢。我使用的是MSVC++2013,这就是问题所在。问题被标记为c++11
,但这并不能解释为什么版本很重要。