pre*_*ous 15 c++ language-lawyer value-initialization list-initialization c++14
由代码中的clang 3.5.0和gcc 4.9.1生成的可执行文件
#include <iostream>
struct Foo
{
Foo() { std::cout << "Foo()" << std::endl; }
Foo(int x) { std::cout << "Foo(int = " << x << ")" << std::endl; }
Foo(int x, int y) { std::cout << "Foo(int = " << x << ", int = " << y << ")" << std::endl; }
};
int main() // Output
{ // ---------------------
auto a = Foo(); // Foo()
auto b = Foo(1); // Foo(int = 1)
auto c = Foo(2, 3); // Foo(int = 2, int = 3)
auto d = Foo{}; // Foo()
auto e = Foo{1}; // Foo(int = 1)
auto f = Foo{2, 3}; // Foo(int = 2, int = 3)
auto g = Foo({}); // Foo(int = 0) <<< Why?
auto h = Foo({1}); // Foo(int = 1)
auto i = Foo({2, 3}); // Foo(int = 2, int = 3)
}
Run Code Online (Sandbox Code Playgroud)
表现为评论.
从cppreference:cpp/language/list初始化:
Run Code Online (Sandbox Code Playgroud)[...] T( { arg1, arg2, ... } ) (7) [...]类型T对象的列表初始化的效果是:
如果
T是聚合类型,则执行聚合初始化.否则,如果braced-init-list为空并且
T是具有默认构造函数的类类型,则执行值初始化.Run Code Online (Sandbox Code Playgroud)[...]
我总结说Foo({})应该调用默认构造函数.
错误在哪里?
Col*_*mbo 18
默认构造函数仅适用于使用一对大括号的情况:
auto a = Foo(); // Foo()
auto b = Foo{}; // Foo()
Run Code Online (Sandbox Code Playgroud)
Foo({})相反,它只会调用带有空列表作为参数的构造函数,copy-list-initialize选择任何构造函数的参数.[dcl.init]/16:
如果目标类型是(可能是cv限定的)类类型:
- 如果初始化是直接初始化[...],则考虑构造函数.列举了适用的构造函数(13.3.1.3),并通过重载解析(13.3)选择最佳构造函数.调用所选的构造函数来初始化对象,初始化表达式或 表达式列表作为其参数.如果没有构造函数适用,或者重载决策是不明确的,则初始化是错误的.
你有一个参数:空的braced-init-list.有一个列表初始化序列转换{}为,int因此构造函数Foo(int)由重载决策选择.该参数初始化为零,因为它{}意味着一个值初始化,对于标量来说,这意味着零初始化.
cppreferences文档中也没有错误:对于(7),它表示
7)在函数化转换表达式或其他直接初始化中,使用braced-init-list作为构造函数参数
这显然导致与上述引用相同的结果:使用(empty)braced-init-list调用构造函数.