我逐渐积累了一些关于语言初始化语法的开放性问题。当一个人不知道要搜索什么或者不知道正确的术语时,搜索答案有时会相对困难。
我在下面的评论中表达的假设是否正确,如果没有,实际发生了什么?我正在使用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
答案 0 :(得分:1)
初始化是一个令人困惑的主题,因为各种形式的初始化(直接初始化,列表初始化,值初始化,等)并非都是互斥的。
如果你很好奇,我会阅读C ++ 11标准并阅读所有血腥细节。这是一个逐行分析。
struct Foo{};
由于Foo
是类类型,Foo
的默认初始化调用默认构造函数(8.5 [dcl.init]第6段)。
由于Foo
是没有用户提供的构造函数的非联合类类型,Foo
的 value-initialization 需要零初始化然后调用隐式声明的默认构造函数,如果它是非平凡的。 (8.5 [dcl.init]第7段)。
在这种情况下,隐式声明的默认构造函数是微不足道的(12.1 [class.ctor],第5段),相当于Foo::Foo() {}
( Id。,第6段)。
Foo
是一个聚合,可以通过初始化列表进行初始化。 (8.5.1 [dcl.init.aggr],第1段)
Foo;
III族形成。但是,声明Foo Foo;
有效,并声明了Foo
类型Foo
的变量。表达式Foo;
将变为有效。不用说,你不应该这样做。
Foo();
这是显式类型转换。由于Foo
是非数组完整对象类型,因此该表达式创建类型为Foo
的prvalue,它是值初始化的。 (5.2.3 [expr.type.conv]第2段)。
Foo{};
这也是一个显式类型转换,它创建一个Foo
类型的prvalue,它是直接列表初始化的( Id。,第3段)。由于 braced-init-list 为空且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段)。它通过 braced-init-list Foo
的聚合初始化构造临时{}
,将临时Foo
绑定到右值引用,{{1} },并调用Foo&&
隐式定义的移动赋值运算符(12.8 [class.copy],第20-21段)。
Foo
这将调用默认初始化(8.5 [dcl.init],第11段)。
Foo f;
这是列表初始化,因为初始化程序是 braced-init-list (8.5 [dcl.init],第16段)。具体来说,它是 direct-list-initialization (8.5.4 [dcl.init.list],第1段)。与Foo f{};
的情况一样,执行值初始化。
Foo{}
这是复制初始化(8.5 [dcl.init],第14段)。同样,由于初始化程序是 braced-init-list ,因此它是列表初始化;具体而言, copy-list-initialization (8.5.4 [dcl.init.list],第1段)。再次,执行值初始化。
Foo f={};
这确实是一个函数声明,因为可以解释为函数声明或对象声明的语句总是被解释为前者(8.2 [dcl.ambig.res],第1段)。
Foo f();
这可以解释为既不是有效的对象声明也不是有效的函数声明,因此它是不正确的。
Foo f()={};
实际上,这是一个函数定义。
答案 1 :(得分:0)
在考虑之后,我得出了以下结论:
Foo f;
是默认初始化。Foo();
,Foo{};
和Foo f{};
是值初始化。Foo f={};
是聚合初始化。Foo()={};
和Foo{}={};
实际上是多个操作:如果我是正确的,Foo()
的值初始化,则按照通过{}
的第二个值初始化(类型由编译器推导),最后以赋值操作结束(由默认赋值运算符)。Foo f();
被视为函数声明Foo f(){}
是一个功能定义