Direct-initialization
从显式的构造函数参数集初始化对象。
目录 |
语法
T
object
(
arg
);
T
object
|
(1) | ||||||||
T
object
{
arg
};
|
(2) | (C++11 起) | |||||||
T
(
other
)
T
|
(3) | ||||||||
static_cast<
T
>(
other
)
|
(4) | ||||||||
new
T
(
args, ...
)
|
(5) | ||||||||
Class
::
Class
()
:
member
(
args, ...
)
{
...
}
|
(6) | ||||||||
[
arg
]() {
...
}
|
(7) | (C++11 起) | |||||||
说明
直接初始化在以下情况下执行:
直接初始化的效果是:
-
如果
T是数组类型,
|
(C++20 前) |
struct A { explicit A(int i = 0) {} }; A a[2](A(1)); // OK:用 A(1) 初始化 a[0],用 A() 初始化 a[1] A b[2]{A(1)}; // 错误:对 b[1] 进行隐式复制列表初始化时 // 从 {} 选择了 explicit 构造函数 |
(C++20 起) |
-
如果
T是类类型,
| (C++17 起) |
-
-
对
T的构造函数进行检查,并通过重载解析选择最佳匹配项。随后调用该构造函数来初始化对象。
-
对
struct B { int a; int&& r; }; int f(); int n = 10; B b1{1, f()}; // OK,生命周期被延长 B b2(1, f()); // 格式正确,但存在悬垂引用 B b3{1.0, 1}; // 错误:窄化转换 B b4(1.0, 1); // 格式正确,但存在悬垂引用 B b5(1.0, std::move(n)); // OK |
(since C++20) |
-
否则,若
T为非类类型但源类型为类类型,则检查源类型及其基类(若存在)的转换函数,并通过重载决议选择最佳匹配。随后使用选定的用户定义转换将初始化表达式转换为被初始化的对象。 -
否则,若
T为 bool 且源类型为 std::nullptr_t ,则初始化对象的值为 false 。 -
否则,如有必要,使用
标准转换
将
other
的值转换为
T的 cv 未限定版本,且被初始化对象的初始值为(可能经过转换的)该值。
注释
直接初始化比复制初始化更宽松:复制初始化仅考虑非 显式 构造函数和非显式用户定义的 转换函数 ,而直接初始化考虑所有构造函数和所有用户定义的转换函数。
当使用直接初始化语法 (1) (圆括号形式)的变量声明与 函数声明 存在歧义时,编译器始终选择函数声明。这种消歧规则有时有违直觉,被称为 最令人烦恼的解析 。
#include <fstream> #include <iterator> #include <string> int main() { std::ifstream file("data.txt"); // 以下是一个函数声明: std::string foo1(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>()); // 它声明了一个名为 foo1 的函数,其返回类型为 std::string, // 第一个参数类型为 std::istreambuf_iterator<char> 且名称为 "file", // 第二个参数无名称且类型为 std::istreambuf_iterator<char>(), // 该类型会被重写为函数指针类型 std::istreambuf_iterator<char>(*)() // C++11 之前的解决方案(用于声明变量)- 在其中一个参数外添加额外括号: std::string str1((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>()); // C++11 之后的解决方案(用于声明变量)- 对任意参数使用列表初始化: std::string str2(std::istreambuf_iterator<char>{file}, {}); }
示例
#include <iostream> #include <memory> #include <string> struct Foo { int mem; explicit Foo(int n) : mem(n) {} }; int main() { std::string s1("test"); // 来自 const char* 的构造函数 std::string s2(10, 'a'); std::unique_ptr<int> p(new int(1)); // 正确:允许显式构造函数 // std::unique_ptr<int> p = new int(1); // 错误:构造函数为显式 Foo f(2); // f 为直接初始化: // 构造函数参数 n 从右值 2 进行拷贝初始化 // f.mem 从参数 n 进行直接初始化 // Foo f2 = 2; // 错误:构造函数为显式 std::cout << s1 << ' ' << s2 << ' ' << *p << ' ' << f.mem << '\n'; }
输出:
test aaaaaaaaaa 1 2