<: 无法开始模板参数列表

17

我在使用g++编译器时遇到了一个错误 <: cannot begin a template argument list。

代码如下:

template<typename T> class SomeClass;
class Class;

SomeClass<::Class>* cls;

1
新标准(C++0x)解决了类似于 A<B<C>> 的问题。它也解决了这个问题吗?顺便说一句,微软编译器在这方面不会报错(我知道从技术上讲它们应该报错,但是不报错很好)。 - Armen Tsirunyan
@ArmenTsirunyan 是的,这个问题在 C++0x 中得到了解决,后来成为了 C++11。尽管 >> 的修复是在第 14.3 节中完成的,但 <:: 的修复是最大匹配规则的修改。因此,两个问题都很烦人,但是涉及的核心问题不同。我在我的回答中详细说明了这一点。 - Shafik Yaghmour
4个回答

35
根据最长匹配分词原则,有效的C++标记必须收集/具有尽可能多的连续字符。 <:是一个双字符符号(符号[的另一种表示方式)。
                           Digraph  Equivalent
                              <:          [
                              :>          ]
                              <%          {
                              %>          }
                              %:          #

所以SomeClass<::Class>* cls;被解释为SomeClass[:Class>* cls;,这没有任何意义。

解决方案:在<:之间添加一个空格。

  SomeClass< ::Class>* cls;
            ^
            | 
           White Space

10

试试以下方法:

SomeClass< ::Class>* cls;

你可以在这个问题中了解更多关于 C 和 C++ 中的双字符(digraph)的信息。也可以参考这个问题了解三字符(trigraph)的用途。


7

使用C++11后,对于这个问题的答案有一些变化。

C++11之前

在C++11之前,最大匹配规则被用于词法分析中以避免歧义,并通过尽可能地获取尽量多的元素来形成有效令牌,导致了以下问题:

<::

生成以下标记如下:
<: :

"<:"是一个双字母组合,它被翻译为[,因此你最终得到的是:"
SomeClass[:Class>* cls;

这不是有效的代码。

我们可以通过查看C++草案标准第2.4预处理标记来确认这一点,其中写道:

如果输入流已解析为预处理标记到给定字符,则下一个预处理标记是最长的字符序列,即使这会导致进一步的词法分析失败。

并提供了一些示例,包括以下经典的最大匹配问题:

[示例:程序片段x+++++y被解析为x ++ ++ + y,这违反了内置类型的增量运算符的约束,即使解析x ++ + ++ y可能会产生正确的表达式。 ——结束示例]

C++11

在C++11中,这种情况发生了变化,为此制定了一项规则,并在C++11草案标准中添加了以下内容:

否则,如果接下来的三个字符是<::,并且随后的字符既不是:也不是>,则<将作为预处理器标记单独处理,而不作为备选标记<:的第一个字符。

添加到第2.5预处理标记。因此,这段代码在C++11中不再产生错误。

这一变化来自缺陷报告:1104


1

在 < 字符周围添加空格:

SomeClass < ::Class > * cls;

你实际上只需要将<和:分开,但是我喜欢对称。

喜欢对称性的人会加一 - Mawg says reinstate Monica

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