带有空括号的默认构造函数

Default constructor with empty brackets

提问人:Martin Beckett 提问时间:10/8/2008 最后编辑:Jarod42Martin Beckett 更新时间:12/4/2019 访问量:40018

问:

是否有任何充分的理由表明一组空的圆括号(括号)对于调用 C++ 中的默认构造函数无效?

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

MyObject  object();  // error

我似乎每次都自动输入“()”。有没有充分的理由不允许这样做?

C 构造函数 default-constructor c++-faq most-vexing-parse

评论

0赞 Adam Mitz 10/8/2008
有人应该为此想出一个更好的标题,但我想不出那会是什么。至少拼出“构造函数”来帮助搜索引擎。
1赞 Albert 8/28/2010
这只是 C++ 上下文敏感的另一个很好的例子。如果是一个类,则问题中的示例代码也会失败。blah
1赞 Milan 11/12/2020
我注意到的一件事是,如果我只有默认构造函数,那么如果我使用例如,编译器不会给出任何错误 照常工作,不会出现任何错误!有人可以解释一下为什么吗?我的意思是我还没有在我的 ...所以它应该给出一个错误,对吧?提前致谢!()MyObject objectMyObject object()main

答:

52赞 Nemanja Trifunovic 10/8/2008 #1

函数声明使用相同的语法 - 例如函数,不带参数并返回objectMyObject

评论

2赞 Martin Beckett 10/8/2008
谢谢 - 我不会想到在其他代码的中间声明一个函数。但我想这是合法的。
11赞 Fred Larson 10/8/2008 #2

因为编译器认为它是一个函数的声明,它不带任何参数并返回一个 MyObject 实例。

126赞 1800 INFORMATION 10/8/2008 #3

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

int MyFunction(); // clearly a function
MyObject object(); // also a function declaration

评论

1赞 Milan 11/12/2020
但它应该给出一个错误,对吧?因为我们还没有定义函数,对吧?您能否详细说明一下?我现在很困惑。提前非常感谢您!object()
0赞 Milan 11/12/2020
顺便说一句,在我的 中,我什至尝试了这些:例如 、、、等,它们都可以工作,即我的程序被编译时没有任何错误!但是,我还没有定义任何这些函数,所以,我应该会遇到错误,对吧?mainany_variable_name random_function_name()int func1()double func2()void func3()
2赞 1800 INFORMATION 11/16/2020
@Milan 如果您实际尝试调用这些函数,我会期望链接器错误。否则,它们只是声明
7赞 Black 10/8/2008 #4

我猜,编译器不知道这句话是否:

MyObject 对象();

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

5赞 Michael Burr 10/8/2008 #5

正如多次提到的,这是一个宣言。这是向后兼容性的方式。由于其遗产,C++ 的众多领域之一,它们愚蠢/不一致/痛苦/虚假。

193赞 Constantin 10/8/2008 #6

最令人烦恼的解析

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

同一问题的另一个实例:

std::ifstream ifs("file.txt");
std::vector<T> v(std::istream_iterator<T>(ifs), std::istream_iterator<T>());

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

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

std::vector<T> v((std::istream_iterator<T>(ifs)), std::istream_iterator<T>());

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

std::vector<T> v{std::istream_iterator<T>{ifs}, std::istream_iterator<T>{}};

这样一来,就不可能将其解释为函数声明。

评论

8赞 Marc Mutz - mmutz 8/8/2009
吹毛求疵:您可以在函数中声明函数。它在 C 中被称为局部函数,至少在 C++ 中也允许使用 -style。extern "C" foo();
4赞 Casebash 10/29/2010
这怎么能解释为一个函数呢?
14赞 Constantin 10/30/2010
@Casebash,是返回类型; 是函数名称; 打开正式参数列表; 是第一个参数的类型; 是第一个参数的名称,周围被有效忽略;二是第二个参数的类型,它是未命名的,围绕它也被忽略;');' 关闭参数列表和函数声明。std::vectorv(std::istream_iteratorifs()ifsstd::istream_iterator()
2赞 bartolo-otrit 9/28/2012
涉及表达式语句和声明的语法存在歧义:将函数样式显式类型转换作为其最左侧子表达式的表达式语句可能与第一个声明符以 (.在这些情况下,声明是声明。(C++ ISO/IEC (2003) 6.8.1)
12赞 CTMacUser 2/15/2014
@Constantin,第二个参数后面的括号不会被忽略。第二个参数不是 a,而是指向一个函数的指针/引用,该函数不带任何参数并返回 .std::istream_iteratoristream_iterator
7赞 dalle 10/8/2008 #7

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

MyObject object1 = MyObject();
MyObject object2 = MyObject(object1);

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

auto object1 = MyObject();
auto object2 = MyObject(object1);

评论

5赞 Casebash 10/29/2010
这需要复制构造函数,并且效率低下
9赞 dalle 10/29/2010
@Casebash:编译器可能足够聪明,可以使用一些类似优化的优化来防止它效率低下。RVO
2赞 Stefan 11/4/2014
“可能”的意思是“我在猜测”。关于优化,人们通常不想猜测,而是采取明确的方式。
7赞 Lightness Races in Orbit 6/26/2015
@Stefan:你不需要“猜测”;在所有主流编译器中,复制省略都会发生,这种情况已经持续了十多年。并不是说这是好的代码。
1赞 M.M 2/23/2022
由于 C++17 没有复制/移动,因此行为被定义为与直接初始化相同
5赞 Andreas DM 6/28/2015 #8

从 n4296 [dcl.init]:

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

C++ 链接
C++14 链接

评论

3赞 Felipe Tonello 11/22/2016
你能为源添加一个链接吗?
3赞 Hitokage 10/19/2017 #9

正如其他人所说,它是一个函数声明。从 C++11 开始,如果需要查看空的内容,则可以使用大括号初始化,该空内容明确告诉您使用了默认构造函数。

Jedi luke{}; //default constructor