关于struct初始化语法复杂性的问题

时间:2014-02-17 06:46:50

标签: c++ syntax initialization

我逐渐积累了一些关于语言初始化语法的开放性问题。当一个人不知道要搜索什么或者不知道正确的术语时,搜索答案有时会相对困难。

我在下面的评论中表达的假设是否正确,如果没有,实际发生了什么?我正在使用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

2 个答案:

答案 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(){}是一个功能定义