为什么string concat宏不能用于这个"+"情况?

Hon*_*hen 4 c++ macros gcc clang

简短的问题:

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

#define OP(var) operator##var
Run Code Online (Sandbox Code Playgroud)

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
}
Run Code Online (Sandbox Code Playgroud)

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

error: pasting formed 'operator+', an invalid preprocessing token
Run Code Online (Sandbox Code Playgroud)

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

error: pasting "operator" and "+" does not give a valid preprocessing token
Run Code Online (Sandbox Code Playgroud)

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

M.M*_*M.M 5

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

#define PASTE(a,b) a##b

int main()
{
     int i = 0;
     i PASTE(+,+);
     // i == 1 now
}
Run Code Online (Sandbox Code Playgroud)

##操作员是用于产生一个有效的预处理标记从其它预处理标记.粘贴的结果必须是有效的预处理标记.所以这是无效的:

PASTE(i,++)
Run Code Online (Sandbox Code Playgroud)

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

可能的令牌列表是(N3797):

  • 头名
  • 识别码
  • PP-数
  • 字符文字
  • 用户定义字符的字面
  • 字符串字面量
  • 用户定义-字串文本
  • 预处理-OP-或-PUNC
  • 每个非白色空格字符不能是上述之一

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

在你的代码中,operator+有两个令牌:operator+.所以你不要用它来构建它##; 你只做一个然后另一个.

#define OP(punc) operator punc
Run Code Online (Sandbox Code Playgroud)