首先是模板实例化与宏扩展

What comes first - template instantiation vs. macro expansion?

本文关键字:扩展 实例化      更新时间:2023-10-16

让我们考虑一个这样的代码示例(它只是一个将definetemplate结合起来的人为示例,不要寻找任何意义):

#define COMMA ,
template <typename A> class Test
{
public:
    Test(){}
    void Foo(A var COMMA int test);
};
Test<int> Knarz;

问题:

我的假设是否正确,首先预处理器将搜索/替换所有出现的逗号,其次编译器将按该顺序实例化任何模板?

随访:

如果上面的答案是"",正如我希望的那样,你能解释为什么这个使用模板和定义的解决方案有效吗?

处理器在编译本身完成之前运行,因此您假设预处理器将在模板实例化之前替换COMMA是正确的。

对于您的后续工作:该解决方案与模板关系不大。问题是预处理器会将大括号内的逗号作为宏的参数分隔符,因为它不会解析C++代码以查看它是模板参数的分隔符。因此,COMMA宏用于仅在替换MOCK_CONSTANT_METHOD0后插入用于分隔模板参数的,。然而,我不确定这是否保证有效,因为我不知道记忆宏替换顺序的保证。如果在MOCK_CONSTANT_METHOD0之前替换COMMA,一切都会分崩离析,代码再次无法编译。

编辑:在研究了标准之后,我认为解决方案通常应该有效,因为预处理器会首先找到MOCK_CONSTANT_METHOD0并替换它。只有这样,它才会检查替换的结果以查找COMMA宏。虽然不能保证。

首先是宏和模板,实际上是宏在编译之前只对现有代码应用更改。因此,在此解决方案中,逗号将生成一个模板代码,如下所示:

MOCK_CONSTANT_METHOD0(aMethod, const QMap<QString,QString>());

在编译之前。

所以对于第二个问题:

它与 gmock 框架的工作方式有关,实际上MOCK_CONSTANT_METHOD0是一个宏,因此该行将被转换为其他内容。Markus Mayr 说逗号将被翻译为参数分隔符,因此它与在这种情况下如何转换 gmock 宏有关,我想首先将替换模拟宏,然后逗号将在内部应用,这就是为什么它确实适用于宏而不仅仅是逗号的原因。

预处理器是第一个。

我认为引用的解决方案是一个非常糟糕的主意,因为它取决于预处理器执行其替换的顺序。由于整个字符仅用于防止预处理器在模板参数列表中的逗号上阻塞,因此最好使用 typedef。

翻译有 9 个阶段。

我的假设是否正确,首先预处理器将 搜索/替换所有出现的COMMA,其次编译器将 按该顺序实例化任何模板?

COMMA令牌在第 4 阶段被替换。
模板在第 8 阶段实例化。