简体   繁体   English

C ++解析器如何区分比较和模板实例化?

[英]How does a parser for C++ differentiate between comparisons and template instantiations?

In C++, the symbols '<' and '>' are used for comparisons as well as for signifying a template argument. 在C ++中,符号“<”和“>”用于比较以及表示模板参数。 Thus, the code snippet 因此,代码片段

[...] Foo < Bar > [...]

might be interpreted as any of the following two ways: 可能被解释为以下两种方式中的任何一种:

  • An object of type Foo with template argument Bar Foo类型的对象,带有模板参数Bar
  • Compare Foo to Bar, then compare the result to whatever comes next 将Foo与Bar进行比较,然后将结果与下一步的结果进行比较

How does the parser for a C++ compiler efficiently decide between those two possibilities? C ++编译器的解析器如何有效地决定这两种可能性?

If Foo is known to be a template name (eg a template <...> Foo ... declaration is in scope, or the compiler sees a template Foo sequence), then Foo < Bar cannot be a comparison. 如果已知Foo是模板名称(例如template <...> Foo ...声明在范围内,或者编译器看到template Foo序列),那么Foo < Bar不能是比较。 It must be a beginning of a template instantiation (or whatever Foo < Bar > is called this week). 它必须是模板实例化的开始(或本周调用的任何Foo < Bar > )。

If Foo is not a template name, then Foo < Bar is a comparison. 如果Foo 不是模板名称,那么Foo < Bar就是一个比较。

In most cases it is known what Foo is, because identifiers generally have to be declared before use, so there's no problem to decide one way or the other. 在大多数情况下,已知Foo是什么,因为标识符通常必须在使用前声明,因此决定一种方式或另一种方式没有问题。 There's one exception though: parsing template code. 但有一个例外:解析模板代码。 If Foo<Bar> is inside a template, and the meaning of Foo depends on a template parameter, then it is not known whether Foo is a template or not. 如果Foo<Bar>在模板中,并且Foo的含义取决于模板参数,则不知道Foo是否是模板。 The language standard directs to treat it as a non-template unless preceded by the keyword template . 语言标准指示将其视为非模板,除非前面有关键字template

The parser might implement this by feeding context back to the lexer. 解析器可以通过将上下文反馈给词法分析器来实现这一点。 The lexer recognizes Foo as different types of tokens, depending on the context provided by the parser. 词法分析器将Foo识别为不同类型的标记,具体取决于解析器提供的上下文。

The important point to remember is that C++ grammar is not context-free. 要记住的重要一点是C ++语法不是无上下文的。 Ie, when the parser sees Foo < Bar (in most cases) knows that Foo refers to a template definition (by looking it up in the symbol table), and thus < cannot be a comparison. 即,当解析器看到Foo < Bar (在大多数情况下)知道Foo引用模板定义时(通过在符号表中查找),因此<不能是比较。

There are difficult cases, when you literally have to guide the parser. 当你需要引导解析器时,有一些困难的情况。 For example, suppose that are writing a class template with a template member function, which you want to specialize explicitly. 例如,假设正在编写具有模板成员函数的类模板,您希望将其显式专门化。 You might have to use syntax like: 您可能必须使用如下语法:

 a->template foo<int>();

(in some cases; see Calling template function within template class for details) (在某些情况下;有关详细信息,请参阅模板类中的调用模板函数

Also, comparisons inside non-type template arguments must be surrounded by parentheses, ie: 此外,非类型模板参数内的比较必须用括号括起来,即:

foo<(A > B)>

not

foo<A > B>

Non-static data member initializers bring more fun: http://open-std.org/JTC1/SC22/WG21/docs/cwg_active.html#325 非静态数据成员初始化器带来更多乐趣: http//open-std.org/JTC1/SC22/WG21/docs/cwg_active.html#325

C and C++ parsers are "context sensitive", in other words, for a given token or lexeme, it is not guaranteed to be distinct and have only one meaning - it depends on the context within which the token is used. C和C ++解析器是“上下文敏感的”,换句话说,对于给定的令牌或词汇,它不能保证是不同的并且只有一个含义 - 它取决于使用令牌的上下文。

So, the parser part of the compiler will know (by understanding "where in the source it is") that it is parsing some kind of type or some kind of comparison (This is NOT simple to know, which is why reading the source of competent C or C++ compiler is not entirely straight forward - there are lots of conditions and function calls checking "is this one of these, if so do this, else do something else"). 因此,编译器的解析器部分将知道(通过理解“它在源中的位置”)它正在解析某种类型或某种类型的比较(这不是很容易知道,这就是为什么阅读源代码的原因。有能力的C或C ++编译器并不完全是直接的 - 有很多条件和函数调用检查“这是其中之一,如果这样做,否则做其他事情”)。

The keyword template helps the compiler understand what is going on, but in most cases, the compiler simply knows because < doesn't make sense in the other aspect - and if it doesn't make sense in EITHER form, then it's an error, so then it's just a matter of trying to figure out what the programmer might have wanted - and this is one of the reasons that sometimes, a simple mistake such as a missing } or template can lead the entire parsing astray and result in hundreds or thousands of errors [although sane compilers stop after a reasonable number to not fill the entire universe with error messages] 关键字template可以帮助编译器理解发生了什么,但在大多数情况下,编译器只是知道因为<在另一方面没有意义 - 如果它在EITHER形式中没有意义,那么它是一个错误,那么这只是试图弄清楚程序员可能想要什么的问题 - 这是有时候,一个简单的错误,例如遗漏}template可能导致整个解析误入歧途并导致数百或数千的原因之一错误[虽然理智的编译器在合理的数字后停止,但没有用错误消息填充整个Universe]

Most of the answers here confuse determining the meaning of the symbol (what I call "name resolution") with parsing (defined narrowly as "can read the syntax of the program"). 这里的大多数答案混淆了确定符号的含义(我称之为“名称解析”)和解析 (狭义地定义为“可以读取程序的语法”)。

You can do these tasks separately. 您可以单独执行这些任务。 .

What this means is that you can build a completely context-free parser for C++ (as my company, Semantic Designs does), and leave the issues of deciding what the meaning of the symbol is to a explicitly seperate following task. 这意味着您可以为C ++构建一个完全无上下文的解析器(正如我的公司,Semantic Designs所做的那样),并留下决定符号含义对于明确单独的后续任务的问题。

Now, that task is driven by the possible syntax interpretations of the source code. 现在,该任务由源代码的可能语法解释驱动。 In our parsers, these are captured as ambiguities in the parse. 在我们的解析器中,这些被解析为解析中的歧义

What name resolution does is collect information about the declarations of names, and use that information to determine which of the ambiguous parses doesn't make sense, and simply drop those. 名称解析的作用是收集有关名称声明的信息,并使用该信息来确定哪些不明确的解析没有意义,并简单地删除它们。 What remains is a single valid parse, with a single valid interpretation. 剩下的是一个有效的解析,只有一个有效的解释。

The machinery to accomplish name resolution in practice is a big mess. 在实践中完成名称解析的机制是一个很大的混乱。 But that's the C++ committee's fault, not the parser or name resolver. 但这是C ++委员会的错,而不是解析器或名称解析器。 The ambiguity removal with our tool is actually done automatically, making that part actually pretty nice but if you don't look inside our tools you would not appreciate that, but we do because it means a small engineering team was able to build it. 使用我们的工具去除歧义实际上是自动完成的,使得这部分实际上非常好,但是如果你不查看我们的工具你就不会欣赏它,但我们这样做是因为它意味着一个小型工程团队能够构建它。

See an example of resolution of template-vs-less than on C++s most vexing parse done by our parser. 查看一个解决模板vs-less的解决方案的例子,而不是C ++我们的解析器完成最令人烦恼的解析

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM