为什么“A<0>=0"中的模板id由于大于或等于运算符“>="而不能在没有空间的情况下编译?
template 使用 A = int;void f(A<0=0);//试图声明一个函数 f 接受 int,//使用默认参数 0//按预期工作://void f(A<0> = 0);
这既不能在 GCC 4.9.2 或 Clang 3.5 上编译 - 更不用说 ICC 或 VC++.显然 >=
位被解析为大于或等于运算符.但是,这对于 [temp.names]/3 来说似乎是不正确的:
名称查找(3.4)后发现名称是模板名称或operator-function-id 或 literal-operator-id 指的是一个集合重载函数的任何成员是函数模板,如果这后面跟着一个<
,<
总是作为template-argument-list 并且从不作为小于运算符.解析模板参数列表时,第一个非嵌套>
138 作为结束分隔符 而不是一个大于运算符.[..] [ 示例:
template类 X {/* ...*/};X<1>2>x1;//语法错误X (1 2) >x2;//行
――结束示例 ]
138) 包含 dynamic_cast
的 type-id 的 >
,static_cast
、reinterpret_cast
或 const_cast
,或包含这后续 template-id 的 template-argument 被认为是嵌套的,用于本描述.
是我遗漏了什么还是编译器有问题?
解决方案这是 最大咀嚼的效果原则,它让词法分析器尽可能多地取字符来形成一个有效的标记.这包含在 C++ 标准部分草案 2.5
[lex.pptoken] 中,它说:
否则,下一个预处理标记是最长的序列可以构成预处理标记的字符,即使会导致进一步的词法分析失败.
任何情况,例如您上面引用的情况,都需要为<::
制定一个特定的异常,例如,我们可以在以下代码中看到一个示例:
template类 SomeClass;班级;SomeClass<::Class>* cls;
在这个问题中有介绍,例外情况列在最大咀嚼规则上方的项目符号中:><块引用>
否则,如果接下来的三个字符是 <:: 并且后续字符既不是 : 也不是 >,则 <本身被视为预处理器标记,而不是作为替代标记的第一个字符 <:.
当然还有您在问题中引用的非嵌套 >
.
注意我们可以看到 >=
是来自 2.13
[lex.operators] 部分的预处理器标记,它说:
C++ 程序的词法表示包括许多预处理标记,它们用于预处理器的语法或转换为运算符和标点符号的标记:
并在列表中包含 >=
.
>> 修复
我们可以从修复>>
案例的提案中看到:N1757:直角括号,上面写着(强调我的):
自从引入尖括号以来,C++ 程序员已经对两个连续的右尖括号的事实感到惊讶必须用空格分隔:
#include <向量>typedef std::vector>桌子;//行typedef std::vector<std::vector<bool>>旗帜;//错误
问题是最大咀嚼"的直接后果原理以及 >> 是 C++ 中的有效标记(右移)这一事实.
这个问题是一个小问题,但持续存在,令人讨厌,而且有点尴尬的问题.如果成本合理,似乎因此值得消除惊喜.
本文档的目的是解释允许>>被视为两个右尖括号,以及讨论产生的问题.提出了具体选项和措辞这将实施当前工作文件中的提案.
同时指出>=
的情况:
还值得注意的是,该问题也可以出现在 >>=和 >= 令牌.例如
void func(List= default_val1);void func(List= default_val2);
这两种形式目前都是格式错误的.可能需要也解决了这个问题,但本文不建议这样做.
请注意,此更改破坏了与 C++03 的向后兼容性.
template <int>
using A = int;
void f(A<0>=0); // Attempting to declare a function f taking int,
// with the default argument 0
// Works as expected:
// void f(A<0> = 0);
This neither compiles on GCC 4.9.2 nor Clang 3.5 - let alone ICC or VC++. Apparently the >=
bit is parsed as a greater-or-equal-than operator. However, this seems to be incorrect regarding [temp.names]/3:
After name lookup (3.4) finds that a name is a template-name or that an operator-function-id or a literal- operator-id refers to a set of overloaded functions any member of which is a function template, if this is followed by a
<
, the<
is always taken as the delimiter of a template-argument-list and never as the less-than operator. When parsing a template-argument-list, the first non-nested>
138 is taken as the ending delimiter rather than a greater-than operator. [..] [ Example:template<int i> class X { /* ...*/ }; X< 1>2 > x1; // syntax error X<(1>2)> x2; // OK
― end example ]
138) A
>
that encloses the type-id of adynamic_cast
,static_cast
,reinterpret_cast
orconst_cast
, or which encloses the template-arguments of a subsequent template-id, is considered nested for the purpose of this description.
Am I missing something or is this a compiler bug?
解决方案This an effect of the maximal munch principle, which has the lexical analyzer take as many characters as possible to form a valid token. This is covered in draft C++ standard section 2.5
[lex.pptoken] which says:
Otherwise, the next preprocessing token is the longest sequence of characters that could constitute a preprocessing token, even if that would cause further lexical analysis to fail.
Any cases such as the one you cite above need a specific exception carved out such as this case for <::
, we can see an example in the following code:
template<typename T> class SomeClass;
class Class;
SomeClass<::Class>* cls;
which is covered in this question, the exception is listed in the bullet just above the maximal munch rule:
Otherwise, if the next three characters are <:: and the subsequent character is neither : nor >, the < is treated as a preprocessor token by itself and not as the first character of the alternative token <:.
and of course the non-nested >
which you cite in your question.
Note we can see that >=
is a preprocessor token from section 2.13
[lex.operators] which says:
The lexical representation of C++ programs includes a number of preprocessing tokens which are used in the syntax of the preprocessor or are converted into tokens for operators and punctuators:
and includes >=
in the list.
The >> fix
We can see from the proposal that fixed the >>
case: N1757: Right Angle Brackets which says (emphasis mine):
Ever since the introduction of angle brackets, C++ programmers have been surprised by the fact that two consecutive right angle brackets must be separated by whitespace:
#include <vector> typedef std::vector<std::vector<int> > Table; // OK typedef std::vector<std::vector<bool>> Flags; // Error
The problem is an immediate consequence of the the "maximum munch" principle and the fact that >> is a valid token (right shift) in C++.
This issue is a minor, but persisting, annoying, and somewhat embarrassing problem. If the cost is reasonable, it seems therefore worthwhile to eliminate the surprise.
The purpose of this document is to explain ways to allow >> to be treated as two closing angle brackets, as well as to discuss the resulting issues. A specific option is proposed along with wording that would implement the proposal in the current working paper.
Also points out the >=
case:
It is also worth noting that the problem can also occur with the >>= and >= tokens. For example
void func(List<B>= default_val1); void func(List<List<B>>= default_val2);
Both of these forms are currently ill-formed. It may be desirable to also address this issue, but this paper does not propose to do so.
Note, this change broke backward compatibility with C++03.
相关文章