【问题标题】:Template within template: why "`>>' should be `> >' within a nested template argument list"模板中的模板:为什么嵌套模板参数列表中的“`>>' 应该是 `> >'”
【发布时间】:2011-10-05 10:23:59
【问题描述】:

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

vector<pair<int,int> > s;

如果我们写的时候没有空格:

vector<pair<int,int>> s;

我们会得到一个错误:

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

我认为这是可以理解的,但我不禁想知道,在什么情况下这真的是模棱两可的?

【问题讨论】:

标签: c++ templates compiler-construction vector lexicographic


【解决方案1】:

有时你想要它是>>。考虑

boost::array<int, 1024>>2> x;

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

【讨论】:

  • 但您也可以在 C++0x 中消除歧义:boost::array&lt;int, (1024&gt;&gt;2)&gt; x;
  • @Armen 确实可以。但这是一种“模棱两可”的情况,即程序在解释为 C++03 含义时是有效的。
  • 这确实很有趣。但这仍然不是模棱两可的,因为 >> 的唯一解释会产生一个有效的结构是 >> 作为转变。如果你把它当作两个关闭 > 它是无效的。实际上是否存在两种解释都会产生有效构造的示例?
  • @Armen 对。我对“模棱两可”的解释与人们所期望的不同,因此我把它放在'"'es中。提问者似乎问过“在什么情况下将其视为>>有意义?”。有真正的模棱两可的案例(最近一个测试用例显示在“在 C++0x 上返回 true 和在 C++03 上返回 false 的方法”中,而 IIRC 中显示了一个测试用例,提出了 C+ 的尖括号更改+0x)。
  • 我也在考虑这个问题……有道理。这使我的答案不正确,而您的答案正确。但我不会删除它。 +1 :)
【解决方案2】:

它永远不会模棱两可。事实证明,在 C++0x 中,您不必再在关闭模板 &gt;s 之间写一个空格。

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

【讨论】:

  • 谢谢!虽然我每天都使用 C++0x 编译器(不是为了这段代码),但我真的不太了解它。感谢您的提示:)
  • @Ziyao Wei:不客气,但你真的应该接受@Johannes 的回答,因为我的回答完全错了:)
【解决方案3】:

在当前标准中,标记化是贪婪的,因此&gt;&gt; 将被作为单个标记处理,就像a +++ b 将被解析为a ++ + b 一样。这已经改变和新的标准。虽然它需要编译器实现者做更多的工作,但总的来说它被认为是值得的(而且一些主要的编译器已经将它作为扩展实现了)。

【讨论】:

    【解决方案4】:

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

    历史上的“&gt;&gt;”运算符是一个运算符。它被“识别”为源文件被分解为标记。这些标记随后在语法分析期间在某些上下文中被“理解”(在标记化完成很久之后)。

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

    是的,新的 C++0x 标准改变了这一点,并迫使编译器供应商重新编写他们的实现以消除“&gt;&gt;”在您的情况下的歧义。所以,未来永远不会模棱两可。但是,较旧的 C++ 编译器无法处理此问题,因此暂时保持代码与“&gt;”字符之间的空格兼容可能被认为是“好习惯”。

    【讨论】:

      【解决方案5】:

      通过设置适当的 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&lt;pair&lt;int, int&gt; &gt;。如果您喜欢vector&lt;pair&lt;int, int&gt;&gt;,请使用-std=c++11 或-std=gnu++11 进行编译。

      【讨论】:

        【解决方案6】:

        这取决于编译器。 Visual Studio 不强制要求这样做,即在 g++ 产生错误时两者都有效。我认为这取决于编译器的实现。

        【讨论】:

          【解决方案7】:

          我在用 c++ 编写一个类时遇到了这个问题,我通过执行以下操作解决了这个问题:

          产生与前面提到的相同错误的行:

          findAndDrawContoursFrame(cv::Mat&,cv::Mat&,std::vector<std::vector<cv::Point»&);
          

          通过 GCC 交叉编译器并运行的行:

          findAndDrawContoursFrame(cv::Mat&,cv::Mat&,std::vector< std::vector<cv::Point> >&);
          

          对我来说,这只是对声明解释的错误。

          【讨论】:

            【解决方案8】:

            流语法

            cin &gt;&gt; var;

            对比

            嵌套模板语法

            For&lt;Bar&lt;Barz&gt;&gt;

            编译器的第一阶段,词法分析器将无法识别。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2018-11-26
              • 1970-01-01
              • 2011-10-01
              • 2012-12-06
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多