我知道当我们在另一个模板中使用模板时,我们应该这样写:
vector<pair<int,int> > s;
如果我们在没有空格的情况下编写它:
vector<pair<int,int>> s;
我们会得到一个错误:
`>>' 应该是嵌套模板参数列表中的 `> >'
我认为这是可以理解的,但我不禁想知道,在什么情况下这真的是模棱两可的?
我知道当我们在另一个模板中使用模板时,我们应该这样写:
vector<pair<int,int> > s;
如果我们在没有空格的情况下编写它:
vector<pair<int,int>> s;
我们会得到一个错误:
`>>' 应该是嵌套模板参数列表中的 `> >'
我认为这是可以理解的,但我不禁想知道,在什么情况下这真的是模棱两可的?
有时你希望它是>>
。考虑
boost::array<int, 1024>>2> x;
在 C++03 中,这成功解析并创建了一个 size 数组256
。
它永远不会模棱两可。事实证明,在 C++0x 中,您不必再在关闭>
的 template 之间写一个空格。
问题是编译器更愿意将输入标记为尽可能独立于上下文。由于 C++ 无论如何都不是一种上下文无关的语言,因此仅添加这种特殊情况不会使事情变得特别困难。
在当前标准中,标记化是贪婪的,因此>>
将作为单个标记处理,与a +++ b
解析为a ++ + b
. 这已经改变和新的标准。虽然它需要编译器实现者做更多的工作,但总的来说它被认为是值得的(并且一些主要的编译器已经将其作为扩展实现了)。
C++ 真的很难解析——比大多数其他语言都难。它是一种非常一致的语言,但是在对输入进行标记和理解语法的语法分析之间做了很多工作,以至于对于编译器来说看起来应该很简单的事情通常不是。
历史上的“ >>
”运算符是一个运算符。它被“识别”为源文件被分解为标记。这些标记随后在语法分析期间在某些上下文中被“理解”(在标记化完成很久之后)。
如果您在标记化时进行了语法分析,那么您有“帮助”来帮助区分“ >>
”应该被视为模板声明(或定义)的两个闭包。然而,从历史上看,这并不是历史 C++ 编译器的工作方式。(新的编译器在语法分析和标记化之间做更多的反馈,包括更多的“前瞻”来帮助解决这些歧义。)
是的,新的 C++0x 标准改变了这一点,并迫使编译器供应商重新编写他们的实现以消除 " >>
" 在你的情况下的歧义。所以,未来永远不会模棱两可。>
但是,较旧的 C++ 编译器无法处理此问题,因此暂时将代码与 ' ' 字符之间的空格保持兼容可能被认为是“好习惯” 。
通过设置适当的 C++ 方言来避免此错误。例如,对于 gcc 4.9,以下文件不能编译g++
:
#include <vector>
#include <utility>
int main()
{
using namespace std;
vector<pair<int, int>> v; // compile error!
return 0;
}
让我们深入了解一下:
#include <iostream>
int main()
{
std::cout << __cplusplus << std::endl;
return 0;
}
仅使用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
这取决于编译器。Visual Studio 不强制要求这样做,即在 g++ 产生错误时两者都有效。我认为这取决于编译器的实现。
我在用 C++ 编写一个类时遇到了这个问题,我通过执行以下操作解决了这个问题:
产生与前面提到的相同错误的行:
findAndDrawContoursFrame(cv::Mat&,cv::Mat&,std::vector<std::vector<cv::Point»&);
通过 GCC 交叉编译器并运行的行:
findAndDrawContoursFrame(cv::Mat&,cv::Mat&,std::vector< std::vector<cv::Point> >&);
对我来说,这只是对声明解释的错误。
流语法
cin >> var;
VS
嵌套模板语法
For<Bar<Barz>>
编译器的第一阶段,词法分析器将无法识别。