逐字段构造函数的生成规则是什么?
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不是聚合)。
我发现 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不是聚合)。