构造函数的调用可以被视为函数声明吗?

4
下面的几行内容来自《C++标准库-教程与参考手册》:

通过使用标准输入初始化:

//read all integer elements of the deque from standard input
std::deque<int> c((std::istream_iterator<int>(std::cin)),
(std::istream_iterator<int>()));

不要忘记在初始化参数周围加上额外的括号。否则,这个表达式会做一些非常不同的事情,并且您可能会在后续语句中收到一些奇怪的警告或错误。考虑不使用额外的括号编写该语句:
std::deque<int> c(std::istream_iterator<int>(std::cin),
std::istream_iterator<int>());

在这种情况下,c声明了一个返回类型为deque的函数。它的第一个参数是名为cin的istream_iterator类型,第二个未命名参数是一个不带参数并返回istream_iterator类型的函数。这种结构在语法上既可以作为声明也可以作为表达式。因此,根据语言规则,它被视为声明。额外的括号强制初始化程序不匹配声明的语法。
我可以理解为什么有额外括号的那个不被认为是函数声明,但是没有括号的那个是什么让它成为函数声明呢?因为它的std::cin周围有括号,据我所知,变量的名称不应该包含括号?
我有什么遗漏吗?

3个回答

5

你读到的教程是错误的。正确的内容应该是:

std::deque<int> c(std::istream_iterator<int>(std::cin), std::istream_iterator<int>());

无法解析为函数声明,因为 std::cin 不能是参数名称。不过,如果您删除 std 限定符:

std::deque<int> c(std::istream_iterator<int>(cin), std::istream_iterator<int>());

然后你会得到一个函数声明。

[...] 而且据我所知,变量的名称不可以带有括号?

括号不是名称的一部分。你可以随意放置它们,无论多少个:

int ((((((a)))))) = 12345; // valid code!
a++; // the variable is named 'a'

在GCC上,std::deque<int> c(std::istream_iterator<int>(std::cin), std::istream_iterator<int>())似乎可以编译通过,但是在在线的Comeau编译器上测试时却出现了错误,这让我相信你需要额外的括号(我想在MSVC上测试它,但目前我无法访问)。 - Jesse Good
是的,我也相信这与编译器的实际实现有关,因为在阅读链接的问题后,许多语句在MSVC上不会出现任何错误。 - xcrypt
@Jesse: 嗯,VS2005报错说error C2751: 'std::cin' : 函数参数的名称不能被限定修饰符修饰。恭喜,我们至少找到了一个编译器的错误。我们只需要知道是哪个编译器。我稍后会进一步调查。 :) - Yakov Galka
@ybungalobill: 我认为GCC是错的,参见这个问题,正确的语法应该是在std::istream_iterator<int>()周围加上括号。 - Jesse Good
@Jesse:我也不确定哪种方式更好。标准中唯一相关的部分是“正如6.8中提到的歧义一样,解决办法是将任何可能是声明的结构视为声明。”[dcl.ambig.res]很遗憾它并不明确。如果声明符有合格的ID,那么它是否意味着它不可能是一个声明?换句话说,标准没有说明应该先做什么:1)对象与函数声明消岐 2)从[dcl.meaning]验证规则。 - Yakov Galka

3
如果一条语句既可以被解析为函数原型,也可以被解析为带有构造函数参数的变量声明,则函数原型具有优先权。这与大多数人的预期相反,因此被称为最令人烦恼的解析

1
据我所知,变量名称中不能包含括号。
这个假设是错误的; 括号不是变量名的一部分,它们只是在这种情况下被忽略了。
来自C++标准([dcl.decl]):
声明符:
ptr-声明符
noptr-声明符 参数和限定符 结尾返回类型 ptr-声明符:
noptr-声明符
ptr-运算符 ptr-声明符
noptr-声明符:
声明符-id 属性说明符[opt]
noptr-声明符 参数和限定符
noptr-声明符 [ 常量表达式[opt] ] 属性说明符[opt]
( ptr-声明符 )
以及([dcl.fct]):
参数声明子句:
  • parameter-declaration-listopt ...opt
  • parameter-declaration-list , ...
参数声明列表:
  • parameter-declaration
  • parameter-declaration-list , parameter-declaration
参数声明:
  • attribute-specifieropt decl-specifier-seq declarator
  • attribute-specifieropt decl-specifier-seq declarator = assignment-expression
  • attribute-specifieropt decl-specifier-seq abstract-declaratoropt
  • attribute-specifieropt decl-specifier-seq abstract-declaratoropt = assignment-expression
希望您能按照这些语法定义进行操作,以便了解括号确实是允许的。如果有任何问题,请随时提出,我会尽力澄清。

那里面没有任何危险吗?我想变量声明总是会优先考虑对吧? - xcrypt
@xcrypt:"一个名为()的变量"?你不能使用这个名称定义变量。你能给出你的想法的例子吗? - Oliver Charlesworth
@xcrypt:啊,我明白了,可能是我的措辞不够清晰。现在再看一下。 - Oliver Charlesworth
很抱歉修改一下,我认为应该概括一下:如果你的变量名中包含括号,我可以看到它经常会与函数调用冲突... - xcrypt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接