c++ 具有和不带()的构造函数调用之间的差异

我是C初学者,想了解为什么

return std::list<int>();

需要括号,但是

std::list<int> foo;

不需要括号。这些构造函数调用有什么区别?

这两个都不是构造函数调用。

第一个是一个explicit type conversion,它创建一个类型为std :: list< int>的对象。

第二个是创建一个类型为std :: list< int>的对象的变量定义。

在这两种情况下,默认构造函数(不带参数的构造函数)都将被调用作为创建的一部分。

虽然你可能会看到这样的东西被称为“构造函数调用”,但是没有句法结构可以在C中显式和单独地调用一个构造函数。

当另一个不是因为它们是具有不同语法的两个单独的语言结构而不是调用构造函数的两种方式时,需要括号的原因。

请注意,如果在第二个示例中添加圆括号,则实际上声明一个函数而不是定义变量:

std::list<int> foo; //variable definition
std::list<int> foo(); //function taking no args, returning a std::list<int>

这通常被称为most-vexing-parse. C 11引入了支持初始化来解决这个问题:

std::list<int> foo{}; //variable definition

标准人,对于那些倾向

(N3337的报价)

“但是T()肯定看起来像一个构造函数调用,为什么不这样?

在这种情况下,T()被称为具有功能符号的显式类型转换:

5.2.3 Explicit type conversion (functional notation) [expr.type.conv]

1 […]

2 The expression T(), where T is a simple-type-specifier or typename-specifier for a non-array complete object type or the (possibly cv-qualified) void type, creates a prvalue of the specified type, which is value-initialized (8.5; no initialization is done for the void() case). [Note: if T is a non-class type that is
cv-qualified, the cv-qualifiers are ignored when determining the type of the resulting prvalue (3.10). —end note ]

所以这创建了一个价值初始化的prvalue。

[dcl.init]/7: To value-initialize an object of type T means:

if T is a (possibly cv-qualified) class type (Clause 9) with a user-provided constructor (12.1), then the default constructor for T is called (and the initialization is ill-formed if T has no accessible default
constructor);

— […]

因此,这将调用构造函数作为值初始化的一部分,这是显式类型转换的一部分。如上所述,没有办法直接调用构造函数。标准说:

[class.ctor]/1: Constructors do not have names. A special declarator syntax is used to declare or define the constructor.
The syntax uses:

— an optional decl-specifier-seq in which each decl-specifier is either a function-specifier or constexpr,

— the constructor’s class name, and

— a parameter list

in that order. In such a declaration, optional parentheses around the constructor class name are ignored.

所以构造函数没有名称,我们用语言定义的语法异常声明/定义它们。

“这似乎是一个学术上的区别,这在实践中是否正确?

也许没有。我的意见是,像上面的解释语法一样,纯粹的构造函数调用描绘了构造函数的不正确的图片。构造函数初始化一个对象;它不分配该对象的内存,返回已初始化的对象,将符号绑定到该对象或其他任何由变量定义和类型转换完成的内容。此外,它可能会产生类似OP的混淆,他们期望统一语法,因为他认为这两个结构都是构造函数调用。

为什么在我们有正式的术语避免混乱时使用不精确的synecdoche?

翻译自:https://stackoverflow.com/questions/33079486/difference-between-constructor-calls-with-and-without

转载注明原文:c++ 具有和不带()的构造函数调用之间的差异