模板中的模板:为什么"`>>"应该是嵌套模板参数列表中的">>"

zw3*_*324 50 c++ compiler-construction templates vector lexicographic

我知道当我们在另一个模板中使用模板时,我们应该这样写:

vector<pair<int,int> > s;

如果我们在没有空格的情况下写它:

vector<pair<int,int>> s;

我们会收到一个错误:

嵌套模板参数列表中的`>>'应该是`>>'

我觉得这是可以理解的,但我不禁想知道,在哪种情况下,这真的很模糊?

Joh*_*itb 48

有时你想要>>.考虑

boost::array<int, 1024>>2> x;
Run Code Online (Sandbox Code Playgroud)

在C++ 03中,这成功地解析并创建了一个大小的数组256.

  • 但你也可以在C++ 0x中消除歧义:`boost :: array <int,(1024 >> 2)> x;` (6认同)
  • @Armen 确实可以。但这是一种“模棱两可”的情况,即程序在解释为 C++03 含义时有效。 (2认同)
  • 这确实非常有趣.但是这仍然不是模棱两可的,因为对于产生有效结构的>>的唯一解释是>>作为移位.如果将其视为两个结束>则无效.是否有一个例子,两个解释都会产生有效的结构? (2认同)
  • @Armen对了.我解释"模棱两可"不同于人们所期望的那样,因此我把它放在'''es.提问者似乎已经问过"在什么情况下将它视为>>?".真实模糊的情况(最近一个测试用例显示在"C++ 0x上的返回方式为真,C++ 03上为false"和IIRC中,一个测试用例显示在文件中,提出了C +的尖括号变化+ 0X). (2认同)

Arm*_*yan 28

它永远不会含糊不清.事实证明,在C++ 0x中,您不必再在关闭模板之间写入空格>.

问题是编译器更愿意将输入标记为尽可能独立于上下文.由于C++不是一种与上下文无关的语言,因此只添加这一特殊情况并不会使事情变得特别困难.


Dav*_*eas 11

在当前标准中,标记化是贪婪的,因此>>将作为单个标记处理,其方式与a +++ b将被解析为相同a ++ + b.这已经改变了新标准.虽然它需要编译器实现者的更多工作,但总的来说它是值得的(并且一些主要的编译器已经实现了它作为扩展).


cha*_*ley 7

C++真的难以解析 - 比大多数其他语言困难得多.它是一种非常一致的语言,但是在对输入进行标记化和理解语法的语法分析之间做了很多工作,看起来对于编译器来说它们应该是简单的,通常不是.

历史" >>"运算符是运算符.它被"识别"为源文件被分解为令牌.然后在语法分析期间(在标记化完成之后很久),在某些上下文中"理解"这些标记.

如果您标记化时进行了语法分析,那么您有"帮助"以帮助区分" >>"应被视为模板声明(或定义)的两个闭包.然而,历史上这不是历史C++编译器的工作方式.(新编译器在语法分析和标记化之间做了更多反馈,包括更多"预见"以帮助解决这些歧义.)

是的,新的C++ 0x标准改变了这一点,并迫使编译器供应商重新编写他们的实现以消除>>你的情况中的歧义.所以,它永远不会模棱两可.但是,较旧的C++编译器无法处理,因此将代码与' >'字符之间的空间保持兼容可能被认为是"良好实践" .


And*_*ler 5

通过设置适当的 C++ 方言来避免此错误。例如,对于 gcc 4.9,以下文件无法使用 进行编译g++

#include <vector>
#include <utility>

int main()
{
    using namespace std;
    vector<pair<int, int>> v; // compile error!
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

让我们深入了解一下事情的真相:

#include <iostream>

int main()
{
    std::cout << __cplusplus << std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

仅使用g++ test.cpp此代码编译会打印 199711。尽管 gcc 4.9 于 2014 年发布,但默认的 C++ 方言是带有 GNU 扩展的 C++98。C++98要求我们编写vector<pair<int, int> >. 如果您更喜欢使用或vector<pair<int, int>>进行编译。-std=c++11-std=gnu++11