Que fait ## (double hachage) dans une directive de préprocesseur?

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

La ligne ci-dessus est tirée d'Unreal 4, et je sais que je pourrais la poser sur les forums irréels, mais je pense que c'est une question générale en C ++ qui mérite d'être posée ici.

Je comprends que la première ligne définit une macro, mais je ne suis pas bien familiarisé avec les manigances des préprocesseurs en C ++ et je suis donc perdu là-bas. La logique me dit que la barre oblique inverse signifie que la déclaration continue sur la ligne suivante.

FThreadSafeStaticStat ressemble un peu à un modèle, mais il y a des # en cours et une syntaxe que je n'ai jamais vue auparavant en C ++

Quelqu'un pourrait-il me dire ce que cela signifie? Je comprends que vous n'avez peut-être pas accès à Unreal 4, mais c'est juste la syntaxe que je ne comprends pas.

DavidColson
la source
6
Vous pouvez lire à propos de l'opérateur ## sur cppreference , entre autres
Cubbi
1
##est / pourrait être appelé l'opérateur de concaténation.
dyp le
1
Oh, c'est plutôt cool! Cela explique plutôt beaucoup, merci. Mais pourquoi le mot clé struct est-il utilisé? La ligne ressemble plus à une définition variable
DavidColson
1
Le structintroduit un spécificateur de type élaboré pour autant que je sache.
dyp le
2
Le nom officiel est «opérateur de collage de jetons» car il combine deux jetons de prétraitement pour en produire un autre. Notez qu'il n'est valide que si le résultat est un jeton de prétraitement valide, par exemple vous ne pouvez pas faire + ## 3pour faire +3. (Mais vous pouvez le faire + 3bien sûr, sans l'opérateur)
MM

Réponses:

175

## est l'opérateur du préprocesseur pour la concaténation.

Donc si vous utilisez

DEFINE_STAT(foo)

n'importe où dans le code, il est remplacé par

struct FThreadSafeStaticStat<FStat_foo> StatPtr_foo;

avant que votre code ne soit compilé.

Voici un autre exemple d' un article de mon blog pour expliquer cela plus en détail.

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

Ce programme compilerait et s'exécuterait avec succès et produirait la sortie suivante:

Stumped?

Lorsque le préprocesseur est appelé sur ce code,

  • begin est remplacé par decode(a,n,i,m,a,t,e)
  • decode(a,n,i,m,a,t,e) est remplacé par m ## a ## i ## n
  • m ## a ## i ## n est remplacé par main

Ainsi effectivement, begin()est remplacé par main().

Susam Pal
la source
8
Je ne m'attendais pas à trop réfléchir pour apprendre le comportement de ##, mais je suppose que maintenant je ne l'oublierai jamais? Donc merci.
NicoBerrogorry
2
Il m'a fallu une seconde pour le suivre, mais c'était une réponse fantastique à la question. Merci.
n00dle