为什么字符串连接宏不适用于这种"+"情况?

Why string concat macro doesn't work for this "+" case?

本文关键字:情况 适用于 字符串 连接 不适用 为什么      更新时间:2023-10-16

短问题:

是否允许为字符串连接宏##连接特殊符号,如+, - ?例如,

#define OP(var) operator##var

OP(+)会扩展成operator+吗?

具体问题:

#include "z3++.h"
#include <unordered_map>
namespace z3 {
z3::expr operator+(z3::expr const &, z3::expr const &);
}
typedef z3::expr (*MyOperatorTy)(z3::expr const &, z3::expr const &);
#define STR(var) #var
#define z3Op(var) static_cast<MyOperatorTy>(&z3::operator##var)
#define StrOpPair(var) 
  { STR(var), z3Op(var) }
void test() {
  std::unordered_map<std::string, MyOperatorTy> strOpMap1{
      {"+", static_cast<MyOperatorTy>(&z3::operator+)}};  // fine
  std::unordered_map<std::string, MyOperatorTy> strOpMap2{StrOpPair(+)}; // error
}

对于strOpMap2,使用clang++ -c -std=c++11,它报告:

error: pasting formed 'operator+', an invalid preprocessing token

当使用g++ -c -std=c++11时,它给出:

error: pasting "operator" and "+" does not give a valid preprocessing token

通过阅读gcc的手册,我发现应该可以concat,但是为什么两个编译器都发出错误?

可以粘贴标点符号形成其他标点符号,例如

#define PASTE(a,b) a##b
int main()
{
     int i = 0;
     i PASTE(+,+);
     // i == 1 now
}
##运算符用于从其他预处理令牌生成有效的预处理令牌。粘贴的结果必须是有效的预处理令牌。所以这是无效的:

PASTE(i,++)

,因为i++不是预处理令牌;它是两个相邻的令牌i++

可能的标记列表是(N3797):

  • 头名称
  • <
  • 标识符/gh>
  • pp-number
  • 字符文字量
  • user-defined-character-literal
  • 字符串
  • user-defined-string-literal
  • preprocessing-op-or-punc
  • 每个非空白字符,不能是上述
  • 之一

注:在预处理阶段,关键字不存在;但是在预处理之后,任何应该是关键字的标识符都被(语义上)转换为关键字。因此,您可以通过粘贴较短的单词来构建关键字。

在代码中,operator+是两个令牌:operator+。所以你不建立它与##;你只需要做一个,然后做另一个。

#define OP(punc) operator punc