c++ - 关于结构初始化语法错综复杂的问题

标签 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

最佳答案

初始化是一个令人困惑的话题,因为各种形式的初始化(直接初始化、列表初始化、值初始化等)并不都是相互排斥的。

我浏览了 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/

相关文章:

C++ 检测输入是 Int 还是 String

c++ - 初始化相互引用的对象

java - 变量未初始化

java - 实例初始化器与私有(private)成员

C++多继承构造函数调用

C++ 无法从 vector 访问对象

python - python语法的正则表达式

c++ - 复合 if 语句使用 ? : operator in C

mysql - 触发器中的错误 SQL 语法,MySQL

Python 列表在类实例初始化时应该为空,但事实并非如此。为什么?