一个令人困惑的细节关于最烦人的parsing

我的问题是如何将下面的行作为函数声明进行分析:

vector<int> v(istream_iterator<int>(cin), istream_iterator<int>()); 

我明白最烦恼的parsing的大部分细节,为什么第二个临时迭代器可以被解释为一个函数返回一个迭代器,并且没有参数的types,但是我没有得到的是为什么第一个临时迭代器可以是解释为一种types。 它代表什么types? 我的想法是,这将是某种functiontypes,但我不知道如何使用名称。 它声明的参数是一个istream_iterator<int>名为cin吗? 如果是这样,这是否意味着你可以任意地将参数的名称括起来作为函数? 如果是这样,为什么?

istream_iterator<int>(cin)istream_iterator<int> cin完全相同,但是多余的parens。 这个声明符的语法是从Cinheritance而来的,我认为连C的发明者(Ken Thompson?)都认为这是一个错误。

我已经说过我喜欢Clang(很多)吗?

只要尝试以下(简化代码)

 #include <vector> void foo(std::vector<int>); int main() { std::vector<int> v(int(i), int()); foo(v); } 

在刚重新推出的LLVM试用版中 (刚刚从llvm-gcc变成了clang)。

你会得到:

 /tmp/webcompile/_21483_0.cc:6:21: warning: parentheses were disambiguated as a function declarator std::vector<int> v(int(i), int()); ^~~~~~~~~~~~~~~ /tmp/webcompile/_21483_0.cc:7:3: error: no matching function for call to 'foo' foo(v); ^~~ /tmp/webcompile/_21483_0.cc:3:6: note: candidate function not viable: no known conversion from 'std::vector<int> (int, int (*)())' to 'std::vector<int>' for 1st argument void foo(std::vector<int>); ^ 3 diagnostics generated. 

因此,@ john是对的, int(i)被解释为int i ,即函数的一个命名参数。

是的,这是参数名称。 而且,是的,你可以添加一组括号,因为有时你必须。

如果参数是一个函数指针,那么void (*f)()需要像这样写。

编写标准的人没有花费宝贵的时间准确地指出允许或实际需要括号的情况,所以标准只是说你可以拥有它们。

在标准(2003)中有一个称为Ambiguity resolution的部分,它专用于这种语法。 如果你自己阅读这个部分,我想我不需要进一步解释,因为它有很多的例子非常清楚!

所以在这里你去:

8.2歧义parsing[dcl.ambig.res]

1 – 在一个声明的上下文中,由于函数式强制types转换和6.8中提到的声明之间的相似性而产生的歧义也可能发生。 在这种情况下,select是在函数声明与带有冗余括号的函数声明之间,函数声明使用函数样式强制转换为初始值设定项。 正如6.8中提到的含糊之处一样,决议是考虑任何可能成为声明的结构。 [注意:一个声明可以被一个无效types转换明确地消除,a =可以指示初始化,也可以通过删除参数名称周围多余的括号。 ]

 [Example: struct S { S(int); }; void foo(double a) { S w(int(a)); // function declaration S x(int()); // function declaration S y((int)a); // object declaration S z = int(a); // object declaration } —end example] 

2 – 由于函数样式转换和typesid之间的相似性而产生的模糊可以在不同的上下文中发生。 歧义似乎是在函数式expression式和types声明之间的select。 解决方法是任何可能在其语法上下文中都是types标识的构造应该被认为是一个types标识。

 3- [Example: #include <cstddef> char *p; void *operator new(size_t, int); void foo() { const int x = 63; new (int(*p)) int; // new-placement expression new (int(*[x])); // new type-id } //4 - For another example, template <class T> struct S { T *p; }; S<int()> x; // type-id S<int(1)> y; // expression (ill-formed) //5 - For another example, void foo() { sizeof(int(1)); // expression sizeof(int()); // type-id (ill-formed) } //6 - For another example, void foo() { (int(1)); //expression (int())1; //type-id (ill-formed) } —end example] 

7 – 当一个types名称嵌套在括号中时,另一个歧义出现在函数声明的参数声明子句中,或者作为sizeof或typeid运算符的操作数的typesid中。 在这种情况下,select是在指向函数的指针types参数的声明和在声明符id周围使用冗余括号的参数声明之间进行的。 解决方法是将types名称视为简单types说明符而不是声明者标识。

 [Example: class C { }; void f(int(C)) { } // void f(int (*fp)(C c)) { } // not: void f(int C); int g(C); void foo() { f(1); //error: cannot convert 1 to function pointer f(g); //OK } //For another example, class C { }; void h(int *(C[10])); // void h(int *(*_fp)(C _parm[10])); // not: void h(int *C[10]); —end example]