在预处理指令中,双井号 ## 是用来做什么的?

141
#define DEFINE_STAT(Stat) \
struct FThreadSafeStaticStat<FStat_##Stat> StatPtr_##Stat;

上述行来自Unreal 4,我知道我可以在虚幻论坛上询问,但我认为这是一个普遍的C++问题,应该在这里提出。

我理解第一行定义了一个宏,但我不熟悉C++中的预处理器技巧,所以我迷失了。逻辑告诉我反斜杠意味着声明将继续到下一行。

FThreadSafeStaticStat看起来有点像模板,但其中有#号和一种我从未在C++中见过的语法。

能否有人告诉我这是什么意思?我知道您可能无法访问Unreal 4,但我只是不理解这个语法。


8
你可以在cppreference上了解##运算符的相关信息,除此之外还有其他内容。 - Cubbi
1

可以被称为连接运算符。

- dyp
1
哦,那很酷!它解释了很多,谢谢。但是为什么要使用struct关键字?这行看起来更像是变量定义。 - DavidColson
1
据我所知,struct 引入了一个 复杂类型说明符 - dyp
2
官方名称为“标记粘贴运算符”,因为它将两个预处理标记组合以生成另一个标记。请注意,仅当结果是有效的预处理标记时才有效,例如,您不能执行 + ## 3 来制作 +3。(但是您当然可以不使用运算符执行 + 3 - M.M
2个回答

227

## 是预处理器的连接符。

因此,如果您在代码中使用

DEFINE_STAT(foo)

它将被替换为

struct FThreadSafeStaticStat<FStat_foo> StatPtr_foo;

在编译代码之前。

下面是我博客文章中的另一个示例,以进一步解释这个概念。

#include <stdio.h>

#define decode(s,t,u,m,p,e,d) m ## s ## u ## t
#define begin decode(a,n,i,m,a,t,e)

int begin()
{
    printf("Stumped?\n");
}

这个程序可以成功编译和执行,输出结果如下:
Stumped?

当预处理器在这段代码上运行时,
  • begin 会被替换为 decode(a,n,i,m,a,t,e)
  • decode(a,n,i,m,a,t,e) 会被替换为 m ## a ## i ## n
  • m ## a ## i ## n 会被替换为 main
因此,begin() 实际上被替换为 main()

2
为什么 decode(a,n,i,m,a,t,e) 被替换成 m ## a ## i ## n?这是怎么回事? - Kaiyakha
3
Stumped->Animate->脑筋急转弯之所以有效的TL;DR是因为函数“decode”被设置为具有输入“a”,“n”,“i”,“m”。这些输入被映射到变量“s”,“t”,“u”,“m”。然后,使用预处理器字符串连接指令m ## s ## u ## t将这些变量重新排列成正确的顺序,该指令接受输入“a”,“n”,“i”,“m”并通过更改变量“s”,“t”,“u”,“m”的顺序来重新排列字符以形成单词“main”。我发现绘制值、变量和它们之间的映射很有帮助。 - breakneck645

13
TLDR; ##用于连接字符串,#用于将参数转化为字符串(来自cppreference)。 ##可以将相邻的标识符连接在一起,对于希望将函数作为参数传递的情况非常有用。以下是一个示例,其中foo接受一个函数作为其第一个参数,运算符ab作为第二个和第三个参数:
#include <stdio.h>
enum {my_sum=1, my_minus=2};
#define foo(which, a, b) which##x(a, b)
#define my_sumx(a, b) (a+b)
#define my_minusx(a, b) (a-b)

int main(int argc, char **argv) {
    int a = 2;
    int b = 3;
    printf("%d+%d=%d\n", a, b,  foo(my_sum, a, b));  // 2+3=5
    printf("%d-%d=%d\n", a, b, foo(my_minus, a, b)); // 2-3=-1
    return 0;
}
# 连接参数并将输出用引号括起来。示例如下:
#include <stdio.h> 
#define bar(...) puts(#__VA_ARGS__)
int main(int argc, char **argv) {
    bar(1, "x", int); // 1, "x", int
    return 0;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接