我逐渐积累了一些关于语言初始化语法的开放性问题。当一个人不知道要搜索什么或不知道正确的术语时,搜索答案有时会相对困难。
我在下面的评论中表达的假设是否正确,如果不正确,实际发生了什么?我正在使用 C++11。
struct Foo{};
Foo; //1: Error, this fails for all types, built-in or otherwise
Foo(); //2: rvalue created by an explicit call to the default ctor "Foo::foo()"
Foo{}; //3: rvalue created by specifying an empty initializer list,
// ..at which point is the default constructor called? How
// ..does this actually differ from #2?
Foo={}; //4: Error, why does this syntax not work?
Foo(){}; //5: Error, this one is quite obvious considering #2
Foo()={}; //6: what exactly happens here?
Foo f; //7: instance created by implicit call to default constructor
Foo f{}; //8: instance created by initializer list, similar to #3
Foo f={}; //9: similar to #8
Foo f(); //10: function declaration.
Foo f()={};//11: Error, this is a malformed function declaration
Foo f(){} //12: function definition
最佳答案
初始化是一个令人困惑的话题,因为各种形式的初始化(直接初始化、列表初始化、值初始化等)并不都是相互排斥的。
我浏览了 C++11 标准并阅读了所有血淋淋的细节 ,如果你好奇的话。这是逐行分析。
struct Foo{};
由于
Foo
是类类型,默认初始化为 Foo
调用默认构造函数(8.5 [dcl.init] 第 6 段)。由于
Foo
是一个非 union 类类型,没有用户提供的构造函数,值初始化为 Foo
需要零初始化,然后调用隐式声明的默认构造函数,如果它是非平凡的。 (8.5 [dcl.init] 第 7 段)。在这种情况下,隐式声明的默认构造函数很简单(12.1 [class.ctor],第 5 段),等效于
Foo::Foo() {}
(同上,第 6 段)。Foo
是一个聚合,可以由初始化列表初始化。 (8.5.1 [dcl.init.aggr],第 1 段)Foo;
畸形。然而,声明
Foo Foo;
有效并声明一个名为 Foo
的变量类型 Foo
.表达式 Foo;
然后将变为有效。不用说,你不应该这样做。Foo();
这是一个显式类型转换。由于
Foo
是非数组完整对象类型,此表达式创建类型为 Foo
的纯右值,它是值初始化的。 (5.2.3 [expr.type.conv] 第 2 段)。Foo{};
这也是一个显式类型转换,它创建了一个类型为
Foo
的纯右值。这是直接列表初始化的(同上,第 3 段)。由于花括号初始化列表为空且 Foo
是具有默认构造函数的类类型,对象是值初始化的(8.5.4 [dcl.init.list],第 3 段)。Foo={};
好吧,这没有任何意义。你期望它做什么? (注意:同样,如果
Foo
是一个变量,这将变得明确。)Foo(){};
我同意,很明显这是不正确的,至少作为一种表达方式。然而,它是
Foo
的默认构造函数定义的有效语法。 . (多余的分号是一个空声明。)Foo()={};
这将创建prvalue
Foo()
如前所述,然后对其执行分配。这是允许的,即使 Foo()
是一个右值(13.5 [over.oper],第 7 段)。这个表达式整体上等价于Foo().operator=({})
(5.17 [expr.ass],第 9 段)。它构造了一个临时的 Foo
通过括号初始化列表中的聚合初始化 {}
, 绑定(bind)临时 Foo
到右值引用,Foo&&
, 并调用 Foo
的隐式定义的移动赋值运算符(12.8 [class.copy],第 20-21 段)。Foo f;
这会调用默认初始化(8.5 [dcl.init],第 11 段)。
Foo f{};
这是列表初始化,因为初始化器是一个花括号初始化列表(8.5 [dcl.init],第 16 段)。具体来说,它是直接列表初始化(8.5.4 [dcl.init.list],第 1 段)。如
Foo{}
的情况,执行值初始化。Foo f={};
这是复制初始化(8.5 [dcl.init],第 14 段)。同样,由于初始化器是一个花括号初始化列表,它是列表初始化;具体来说,复制列表初始化(8.5.4 [dcl.init.list],第 1 段)。同样,执行值初始化。
Foo f();
这确实是一个函数声明,因为可以解释为函数声明或对象声明的语句总是被解释为前者(8.2 [dcl.ambig.res],第 1 段)。
Foo f()={};
这既不能解释为有效的对象声明,也不能解释为有效的函数声明,因此它是格式错误的。
Foo f(){}
实际上,这是一个函数定义。
关于c++ - 关于结构初始化语法错综复杂的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21822491/