带空括号的默认构造函数

Mar*_*ett 192 c++ constructor c++-faq default-constructor most-vexing-parse

有没有什么好的理由在C++中调用默认构造函数时,一组空的圆括号(括号)无效?

MyObject  object;  // ok - default ctor
MyObject  object(blah); // ok

MyObject  object();  // error
Run Code Online (Sandbox Code Playgroud)

我似乎每次都自动输入"()".是不是有一个很好的理由不允许这样做?

Con*_*tin 159

最烦恼的解析

这与所谓的"C++最令人烦恼的解析"有关.基本上,任何可以被编译器解释为函数声明的东西都将被解释为函数声明.

同一问题的另一个例子:

std::ifstream ifs("file.txt");
std::vector<T> v(std::istream_iterator<T>(ifs), std::istream_iterator<T>());
Run Code Online (Sandbox Code Playgroud)

v 被解释为具有2个参数的函数声明.

解决方法是添加另一对括号:

std::vector<T> v((std::istream_iterator<T>(ifs)), std::istream_iterator<T>());
Run Code Online (Sandbox Code Playgroud)

或者,如果您有C++ 11和列表初始化(也称为统一初始化)可用:

std::vector<T> v{std::istream_iterator<T>{ifs}, std::istream_iterator<T>{}};
Run Code Online (Sandbox Code Playgroud)

有了这个,就无法将其解释为函数声明.

  • @Casebash,`std :: vector`是返回类型; `v`是函数名; `(`正式打开参数列表;`的std :: istream_iterator`是第一个参数的类型;`ifs`是第一个参数的名称,`()``周围的ifs`有效地忽略;第二个`的std :: istream_iterator`的类型第二个参数,未命名,`()`周围也被忽略;');' 关闭参数列表和函数声明. (11认同)
  • @Constantin,第二个参数后的括号不会被忽略.第二个参数不是`std :: istream_iterator`,而是指向不带参数的函数的指针/引用,并返回一个`istream_iterator`. (10认同)
  • 不,这不是最令人烦恼的解析!您识别_are_的其他情况. (8认同)
  • Nitpick:你_can_声明函数内部的函数.它在C中称为_local functions_,至少`extern"C"foo();在C++中也允许使用`-style. (6认同)
  • 如何将其解释为一种功能? (4认同)
  • 语法中涉及表达式语句和声明的模棱两可:具有函数式显式类型转换作为其最左边子表达式的表达式语句与第一个声明符以(。开头的声明)是无法区分的。是声明(C ++ ISO / IEC(2003)6.8.1) (2认同)

180*_*ION 104

因为它被视为函数的声明:

int MyFunction(); // clearly a function
MyObject object(); // also a function declaration
Run Code Online (Sandbox Code Playgroud)

  • 我实际上更喜欢这个例外答案,关于问题的原因是什么更清楚 (14认同)
  • 非常清晰简单的答案!瞬间我就能理解! (5认同)
  • @Milan如果你真的尝试调用这些函数,我会期望链接器错误。否则它们只是声明 (2认同)

Nem*_*vic 49

相同的语法用于函数声明 - 例如函数object,不带参数和返回MyObject

  • 谢谢 - 我不会想到在其他一些代码的中间声明一个函数。但我认为这是合法的。 (2认同)

Fre*_*son 11

因为编译器认为它是函数的声明,不接受任何参数并返回MyObject实例.


dal*_*lle 8

您还可以使用更详细的构造方式:

MyObject object1 = MyObject();
MyObject object2 = MyObject(object1);
Run Code Online (Sandbox Code Playgroud)

在C++ 0x中,这也允许auto:

auto object1 = MyObject();
auto object2 = MyObject(object1);
Run Code Online (Sandbox Code Playgroud)

  • @Casebash:编译器可能足够聪明,可以使用一些类似RVO`的优化来防止它效率低下. (9认同)
  • @Stefan:你不需要"猜"; 所有主流编译器都会出现复制省略,十多年来情况就是如此.这不是好的代码. (5认同)
  • 这需要复制构造函数并且效率低下 (4认同)
  • “可能”的意思是“我在猜测”。关于优化,人们通常不想猜测,而是采取明确的方式。 (2认同)

Bla*_*ack 7

我猜,编译器不会知道这个语句是否:

MyObject对象();

是构造函数调用或函数原型,声明一个名为object的函数,返回类型为MyObject且没有参数.


Mic*_*urr 5

如前所述,这是一个宣言.这是向后兼容的方式.C++的许多领域之一,由于其遗留问题而愚蠢/不一致/痛苦/虚假.


And*_* DM 5

来自n4296 [dcl.init]:

[注意:
由于initializer()的语法不允许, 因此不是类X 的对象的声明,而是不带参数并返回X的函数的声明。在某些其他初始化上下文中,形式()是允许的( 5.3.4、5.2.3、12.6.2)。 —尾注]X a();

C ++ 11链接
C ++ 14链接

  • 您可以添加源链接吗? (3认同)