用于C++的分析器如何区分比较和模板实例化
How does a parser for C++ differentiate between comparisons and template instantiations?
在C++中,符号"<"和">"用于比较以及表示模板参数。因此,代码片段
[...] Foo < Bar > [...]
可以解释为以下两种方式中的任何一种:
- 带有模板参数栏的 Foo 类型的对象
- 将Foo与Bar进行比较,然后将结果与接下来的结果进行比较
C++编译器的解析器如何有效地在这两种可能性之间做出决定?
如果已知Foo
是模板名称(例如,template <...> Foo ...
声明在范围内,或者编译器看到template Foo
序列(,则Foo < Bar
不能是比较。它必须是模板实例化的开始(或本周调用的任何Foo < Bar >
(。
如果Foo
不是模板名称,则Foo < Bar
是比较。
在大多数情况下,知道Foo
是什么,因为标识符通常必须在使用前声明,因此决定一种或另一种方式没有问题。但有一个例外:解析模板代码。如果Foo<Bar>
在模板内,并且Foo
的含义取决于模板参数,则不知道Foo
是否是模板。语言标准指示将其视为非模板,除非前面有关键字 template
。
解析器可以通过将上下文反馈回词法分析器来实现这一点。词法分析器将Foo
识别为不同类型的标记,具体取决于分析器提供的上下文。
要记住的重要一点是,C++语法不是上下文无关的。 即,当解析器看到Foo < Bar
(在大多数情况下(知道Foo
引用模板定义(通过在符号表中查找它(,因此<
不能进行比较。
在困难的情况下,您必须指导解析器。例如,假设 正在使用模板成员函数编写类模板,您希望显式专用该函数。您可能需要使用如下语法:
a->template foo<int>();
(在某些情况下;有关详细信息,请参阅在模板类中调用模板函数(
此外,非类型模板参数内的比较必须用括号括起来,即:
foo<(A > B)>
不
foo<A > B>
非静态数据成员初始值设定项带来更多乐趣: http://open-std.org/JTC1/SC22/WG21/docs/cwg_active.html#325
C 和 C++ 解析器是"上下文相关的",换句话说,对于给定的标记或词法,它不能保证是不同的并且只有一个含义 - 这取决于使用令牌的上下文。
因此,编译器的解析器部分将知道(通过了解"它在源代码中的位置"(它正在解析某种类型或某种比较(这并不容易知道,这就是为什么阅读有能力的 C 或 C++ 编译器的源代码并不完全直截了当 - 有很多条件和函数调用检查"这是其中之一, 如果是这样,请执行此操作,否则请执行其他操作"(。
关键字 template
帮助编译器了解正在发生的事情,但在大多数情况下,编译器只是知道,因为<
在其他方面没有意义 - 如果它在任何一种形式中都没有意义,那么这是一个错误,所以这只是一个试图弄清楚程序员可能想要什么的问题 - 这是有时的原因之一, 一个简单的错误,如缺少}
或template
,可能会导致整个解析误入歧途,并导致成百上千个错误[尽管理智的编译器在合理的数字后停止,以免用错误消息填充整个宇宙]
这里的大多数答案都混淆了确定符号的含义(我称之为"名称解析"(和解析(狭义地定义为"可以读取程序的语法"(。
您可以单独执行这些任务。
这意味着你可以为C++构建一个完全独立于上下文的解析器(就像我的公司Semantic Designs所做的那样(,并将决定符号含义的问题留给一个明确独立的后续任务。
现在,该任务由源代码的可能的语法解释驱动。 在我们的解析器中,这些在解析中被捕获为歧义。
名称解析的作用是收集有关名称声明的信息,并使用该信息来确定哪些不明确的解析没有意义,然后简单地删除它们。 剩下的是一个有效的解析,有一个有效的解释。
在实践中完成名称解析的机制是一团糟。 但这是C++委员会的错,而不是解析器或名称解析器。使用我们的工具消除歧义实际上是自动完成的,使该部分实际上非常好,但如果您不查看我们的工具,您不会欣赏这一点,但我们这样做是因为这意味着一个小型工程团队能够构建它。
查看模板与小于模板的解析示例,而不是我们的解析器完成的最令人烦恼的解析C++。
- 从C++实例化QML
- 设计一个只能由特定类实例化的类(如果可能的话,通过make_unique)
- 如何创建一个空的全局类并在启动时实例化它
- 在两个类中共享相同的函数调用,并在不需要时避免空实例化
- 约束和显式模板实例化
- 为什么包含windows.h会产生语法错误,从而阻止类的实例化?(C2146,C2065)
- 对象实例化调用构造函数的次数太多
- 如何使用非默认构造函数实例化模板化类
- 静态数据成员模板专用化的实例化点在哪里
- 错误的cv::face FacemarkLBF实例化
- C++的解析器在可以区分比较和模板实例化之前会做什么?
- 为什么 gcc 和 clang 为函数模板的实例化生成不同的符号名称?
- 检查某些类型是否是模板类 std::optional 的实例化
- 我有一个对象,它将在整个程序的持续时间内实例化,但一个类成员不会,我应该动态分配它吗?
- 如何键入定义一个专门的 std::set 模板,使用特定的比较函数实例化
- 无法理解浮点数和对象实例化之间比较的原因
- 为什么没有询问priority_queue实例化中比较器的模板参数
- 用于C++的分析器如何区分比较和模板实例化
- 如何在定义映射/集合时实例化比较函数(函子)
- is_same将类模板实例化与其基类模板进行比较时返回 false