首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >我的值初始化尝试被解释为函数声明,为什么A a(());不能解决它?

我的值初始化尝试被解释为函数声明,为什么A a(());不能解决它?
EN

Stack Overflow用户
提问于 2009-09-15 00:13:23
回答 5查看 19.2K关注 0票数 161

在Stack Overflow教给我的许多东西中,有一个就是所谓的“最烦人的解析”,它的经典演示是这样的:

代码语言:javascript
复制
A a(B()); //declares a function

虽然对于大多数人来说,这直观地看起来是A类型的对象a的声明,将临时B对象作为构造函数参数,但它实际上是函数a的声明,返回A,接受指向返回B的函数的指针,并且本身不带参数。类似地,这条线

代码语言:javascript
复制
A a(); //declares a function

也属于同一类别,因为它声明的不是对象,而是函数。现在,在第一种情况下,解决此问题的通常方法是在B()周围添加额外的一组括号/括号,因为编译器随后会将其解释为对象的声明

代码语言:javascript
复制
A a((B())); //declares an object

但是,在第二种情况下,这样做会导致编译错误

代码语言:javascript
复制
A a(()); //compile error

我的问题是,为什么?是的,我很清楚正确的“变通办法”是把它改成A a;,但我很好奇,在第一个例子中额外的()对编译器做了什么,然后在第二个例子中重新应用它时就不起作用了。A a((B()));变通方法是写入标准的特定异常吗?

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2009-09-15 00:24:32

没有明智的答案,只是因为它没有被C++语言定义为有效的语法……根据语言的定义,是这样的。

如果你在里面有一个表达式,那么它是有效的。例如:

代码语言:javascript
复制
 ((0));//compiles

更简单的put:因为(x)是一个有效的C++表达式,而()不是。

要进一步了解语言是如何定义的,以及编译器是如何工作的,您应该了解Formal language theory,或者更具体地说,了解Context Free Grammars (CFG)和有限状态机等相关内容。如果你对此感兴趣,尽管维基百科的页面还不够,你必须买一本书。

票数 72
EN

Stack Overflow用户

发布于 2011-07-22 01:35:53

这个问题的最终解决方案是尽可能使用C+11统一初始化语法。

代码语言:javascript
复制
A a{};

http://www.stroustrup.com/C++11FAQ.html#uniform-init

票数 39
EN

Stack Overflow用户

发布于 2014-05-19 03:53:51

C函数声明符

首先是C。在C中,A a()是函数声明。例如,putchar具有以下声明。通常,这样的声明存储在头文件中,但是,如果您知道函数的声明是什么样子,就不会阻止您手动编写它们。参数名在声明中是可选的,所以我在本例中省略了它。

代码语言:javascript
复制
int putchar(int);

这使您可以像这样编写代码。

代码语言:javascript
复制
int puts(const char *);
int main() {
    puts("Hello, world!");
}

C还允许您定义以函数为参数的函数,具有良好的可读性语法,看起来像函数调用(好吧,它是可读性的,只要您不返回指向函数的指针)。

代码语言:javascript
复制
#include <stdio.h>

int eighty_four() {
    return 84;
}

int output_result(int callback()) {
    printf("Returned: %d\n", callback());
    return 0;
}

int main() {
    return output_result(eighty_four);
}

正如我所提到的,C允许在头文件中省略参数名,因此头文件中的output_result将如下所示。

代码语言:javascript
复制
int output_result(int());

构造函数中的一个参数

你认不出那个了吗?好吧,让我提醒你一下。

代码语言:javascript
复制
A a(B());

是的,这是完全相同的函数声明。Aintaoutput_resultBint

您可以很容易地注意到C语言与C++的新特性之间的冲突。确切地说,构造函数是类名和圆括号,并用()代替=替代声明语法。通过设计,C++试图与C代码兼容,因此它必须处理这种情况-即使实际上没有人关心。因此,旧的C特性优先于新的C++特性。声明的语法尝试与函数的名称匹配,如果失败,则在使用()恢复到新语法之前。

如果其中一个特性不存在,或者有不同的语法(比如C++11中的{} ),那么这个问题就不会发生在只有一个参数的语法上。

现在你可能会问为什么A a((B()))会工作。好吧,让我们用无用的括号声明output_result

代码语言:javascript
复制
int output_result((int()));

恐怕行不通。语法要求变量不能放在括号中。

代码语言:javascript
复制
<stdin>:1:19: error: expected declaration specifiers or ‘...’ before ‘(’ token

但是,C++在这里需要标准表达式。在C++中,您可以编写以下代码。

代码语言:javascript
复制
int value = int();

和下面的代码。

代码语言:javascript
复制
int value = ((((int()))));

C++要求括号内的表达式为...好吧..。表达式,而不是C所期望的类型。括号在这里没有任何意义。但是,通过插入无用的圆括号,C函数声明将不匹配,并且新语法可以正确匹配(它只需要一个表达式,如2 + 2)。

构造函数中有更多参数

当然,一个论点是好的,但两个呢?这并不是说构造函数可能只有一个参数。带有两个参数的内置类之一是std::string

代码语言:javascript
复制
std::string hundred_dots(100, '.');

这一切都很好(从技术上讲,如果它被写成std::string wat(int(), char()),它将有最令人烦恼的解析,但老实说-谁会写呢?但是让我们假设这段代码有一个令人烦恼的问题。你会假设你必须把所有的东西都放在括号里。

代码语言:javascript
复制
std::string hundred_dots((100, '.'));

事实并非如此。

代码语言:javascript
复制
<stdin>:2:36: error: invalid conversion from ‘char’ to ‘const char*’ [-fpermissive]
In file included from /usr/include/c++/4.8/string:53:0,
                 from <stdin>:1:
/usr/include/c++/4.8/bits/basic_string.tcc:212:5: error:   initializing argument 1 of ‘std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’ [-fpermissive]
     basic_string<_CharT, _Traits, _Alloc>::
     ^

我不确定为什么g++试图将char转换为const char *。无论哪种方式,构造函数都是用一个char类型的值调用的。没有只有一个char类型参数的重载,因此编译器会感到困惑。你可能会问--为什么参数是char类型?

代码语言:javascript
复制
(100, '.')

是的,这里的,是一个逗号操作符。逗号操作符接受两个参数,并给出右边的参数。这并不是很有用,但我的解释是值得大家知道的。

相反,为了解决最麻烦的解析,需要以下代码。

代码语言:javascript
复制
std::string hundred_dots((100), ('.'));

参数在括号中,而不是整个表达式。实际上,只需要将其中一个表达式放在括号中,因为使用C++特性稍微脱离了C语法就足够了。事情把我们带到了零争论的地步。

构造函数中的零参数

您可能已经注意到我的解释中的eighty_four函数。

代码语言:javascript
复制
int eighty_four();

是的,这也会受到最烦人的解析的影响。这是一个有效的定义,如果您创建了头文件,您很可能会看到这个定义(您应该这样做)。添加括号并不能解决这个问题。

代码语言:javascript
复制
int eighty_four(());

为什么会这样呢?好吧,()不是一个表达式。在C++中,您必须将表达式放在括号之间。您不能用C++编写auto value = (),因为()没有任何意义(即使有,就像空元组一样(请参阅Python),它将是一个参数,而不是零)。实际上,这意味着如果不使用C++11的{}语法,就不能使用简写语法,因为没有要放在括号中的表达式,并且函数声明的C语法将始终适用。

票数 31
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1424510

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档