【问题标题】:Behaviour of #define macro expansion in C++C++ 中#define 宏扩展的行为
【发布时间】:2015-02-17 10:00:08
【问题描述】:

我知道如果我们在变量声明中关闭尖括号后不加空格,C++ 会抛出以下错误。

‘>>’ should be ‘> >’ within a nested template argument list

但是如果我在这段代码中使用#define,则不会出现错误。有人可以解释一下吗?

我认为#define只是一个宏扩展,作用类似于find-replace,所以这里声明变量的方式应该是一样的。

如果我用 C++11 编译它也不会发生这个错误。

#include <bits/stdc++.h>
using namespace std;

#define vi vector<int>

int main(){
    //Doesn't work, compile error
    vector<vector<int>> v;

    //Works
    vector<vi> vv;
}

【问题讨论】:

  • 在 C++11 中,&gt;&gt; 通过一个特殊规则变得有效,因为空间要求太烦人了。
  • 如果你对文件运行cpp,你可以看到两个&gt;字符之间添加了一个空格。
  • @MSalters 这不是误导,而是诊断。当集成的预处理器将标记直接提供给翻译阶段 7 时,空白没有明确表示。但是当被要求生成文本输出时,预处理器必须在必要时插入空格以保留标记边界。现代预处理器仅在必要时才会这样做。因此,当您在文本预处理器输出中看到原始文本中不存在的空白时,您可以得出结论,有一些规则要求其两侧的内容保持不同的标记。
  • @Jignesh 这是一个 g++ 实现细节。不能保证它仍然存在或将来会做同样的事情,并且没有其他编译器拥有它。
  • @Jignesh 例如,如果我尝试使用 clang 而不是 g++ 编译您的测试程序,我会收到一条错误消息,test.cc:1:10: fatal error: 'bits/stdc++.h' file not found

标签: c++


【解决方案1】:

宏扩展发生在标记化之后;它不会替换文本,而是替换标记序列。

这意味着,对于宏,vi 的扩展给出了一个 &gt; 标记,与宏调用之后的标记分开。在每种情况下,标记化只会找到一个 &gt; 字符,因此这就是生成的标记。

如果没有宏,“贪婪”标记化规则意味着两个连续的字符被视为单个 &gt;&gt; 标记,直到 C++11 为这种情况添加了一个特殊规则。

【讨论】:

  • 要更清楚地看到这一点,请考虑#define plusi +i。您现在可以写int i = 0; std::cout &lt;&lt; +plusi。预测会发生什么,然后尝试。
  • @MSalters OTOH,任何将其投入生产的人都需要被解雇
  • 考虑到有一个单独的预处理程序cpp 将输出纯文本,这有点违反直觉。我会假设显式预处理,然后编译,与让编译器自己进行预处理是一样的。
  • This experiment 表明预处理器对此非常聪明。当使用cpp 预处理代码时,它确实会生成vector&lt;vector&lt;int&gt; &gt;,其中包含该空间。在其他情况下,它不包括空格。
猜你喜欢
  • 2011-03-02
  • 2014-09-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-07
  • 1970-01-01
相关资源
最近更新 更多