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

The above line is take from Unreal 4, and I know I could ask it over on the unreal forums, but I think this is a general C++ question that warrants being asked here.

I understand the first line defines a macro, however I am not well versed in preprocessor shenanigans in C++ and so I'm lost over there. Logic tells me the backslash means the declaration continues onto the next line.

FThreadSafeStaticStat looks a bit like a template, but there's #'s going on in there and a syntax I've never seen before in C++

Could someone tell me what this means? I understand that you may not have access to Unreal 4, but it's just the syntax I don't understand.

Drew Dormann
  • 59,987
  • 13
  • 123
  • 180
DavidColson
  • 8,387
  • 9
  • 37
  • 50
  • 8
    You can read about ## operator [on cppreference](http://en.cppreference.com/w/cpp/preprocessor/replace#.23_and_.23.23_operators), among other things – Cubbi Apr 09 '14 at 22:23
  • 1
    `##` is/could be called the concatenation operator. – dyp Apr 09 '14 at 22:23
  • 1
    Oh, that's pretty cool! It explains rather a lot, thanks. But why is the struct keyword used? The line looks more like a variable definition – DavidColson Apr 09 '14 at 22:27
  • 1
    The `struct` introduces an *elaborate type specifier* as far as I can tell. – dyp Apr 09 '14 at 22:34
  • 2
    The official name is "token pasting operator" because it combines two preprocessing tokens to produce another. Note that it is only valid if the result is a valid preprocessing token, e.g. you can't do `+ ## 3` to make `+3`. (But you can do `+ 3` of course, without the operator) – M.M Jan 31 '17 at 09:04
  • Possible duplicate of [What are the applications of the ## preprocessor operator and gotchas to consider?](https://stackoverflow.com/questions/216875/what-are-the-applications-of-the-preprocessor-operator-and-gotchas-to-conside) – phuclv Aug 17 '18 at 05:05

2 Answers2

224

## is the preprocessor operator for concatenation.

So if you use

DEFINE_STAT(foo)

anywhere in the code, it gets replaced with

struct FThreadSafeStaticStat<FStat_foo> StatPtr_foo;

before your code is compiled.

Here is another example from a blog post of mine to explain this further.

#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");
}

This program would compile and execute successfully, and produce the following output:

Stumped?

When the preprocessor is invoked on this code,

  • begin is replaced with decode(a,n,i,m,a,t,e)
  • decode(a,n,i,m,a,t,e) is replaced with m ## a ## i ## n
  • m ## a ## i ## n is replaced with main

Thus effectively, begin() is replaced with main().

Susam Pal
  • 32,765
  • 12
  • 81
  • 103
  • 2
    Why `decode(a,n,i,m,a,t,e)` is replaced with `m ## a ## i ## n`? How is that?? – Kaiyakha Jul 28 '22 at 09:25
  • 2
    The TL;DR of why the Stumped->Animate-> brain teaser works is that the function "decode" is set up as having the input "a", "n", "i", "m". These inputs are mapped to the *variables* "s", "t", "u", "m". These variables are then rearranged into the right order with the preprocessor string concatenation directive `m ## s ## u ## t` which takes the input "a", "n", "i", "m" and rearranges the characters to make the word "main" by changing the order of the *variables* "s", "t", "u", "m". I found it helpful to draw the the values and the variables and the mappings between them. – breakneck645 Sep 28 '22 at 14:29
12

TLDR; ## is for concatenation and # is for stringification (from cppreference).

The ## concatenates successive identifiers and it is useful when you want to pass a function as a parameter. Here is an example where foo accepts a function argument as its 1st argument and the operators a and b as the 2nd and 3rd arguments:

#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;
}

The # concatenates the parameter and encloses the output in quotes. The example is:

#include <stdio.h> 
#define bar(...) puts(#__VA_ARGS__)
int main(int argc, char **argv) {
    bar(1, "x", int); // 1, "x", int
    return 0;
}
hmofrad
  • 1,784
  • 2
  • 22
  • 28