Co robi ## (double hash) w dyrektywie preprocesora?

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

Powyższa linia pochodzi z Unreal 4 i wiem, że mógłbym zadać to pytanie na nierealnych forach, ale myślę, że jest to ogólne pytanie C ++, które zasługuje na to, aby je tutaj zadać.

Rozumiem, że pierwsza linia definiuje makro, jednak nie jestem dobrze zaznajomiony z oszustwami preprocesora w C ++, więc pogubiłem się. Logika mówi mi, że odwrotny ukośnik oznacza, że ​​deklaracja przechodzi do następnej linii.

FThreadSafeStaticStat wygląda trochę jak szablon, ale dzieje się tam # i składnia, której nigdy wcześniej nie widziałem w C ++

Czy ktoś mógłby mi powiedzieć, co to oznacza? Rozumiem, że możesz nie mieć dostępu do Unreal 4, ale to tylko składnia, której nie rozumiem.

DavidColson
źródło
6
Można przeczytać o ## operatorem na cppreference między innymi
Cubbi
1
##jest / można by nazwać operatorem konkatenacji.
dyp
1
Och, to całkiem fajne! To dość dużo wyjaśnia, dzięki. Ale dlaczego używane jest słowo kluczowe struct? Linia wygląda bardziej jak definicja zmiennej
DavidColson,
1
O ile wiem, structwprowadza rozbudowany specyfikator typu .
dyp
2
Oficjalna nazwa to „operator wklejania tokenów”, ponieważ łączy dwa tokeny przetwarzania wstępnego w celu utworzenia kolejnego. Zauważ, że jest on ważny tylko wtedy, gdy wynik jest prawidłowym tokenem przetwarzania wstępnego, np. Nie możesz tego + ## 3zrobić +3. (Ale możesz to zrobić + 3oczywiście bez operatora)
MM

Odpowiedzi:

175

## jest operatorem preprocesora do konkatenacji.

Więc jeśli używasz

DEFINE_STAT(foo)

w dowolnym miejscu kodu zostanie zastąpiony przez

struct FThreadSafeStaticStat<FStat_foo> StatPtr_foo;

zanim Twój kod zostanie skompilowany.

Oto kolejny przykład z mojego posta na blogu, aby to wyjaśnić.

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

Ten program skompilowałby się i wykonałby pomyślnie i dałby następujący wynik:

Stumped?

Gdy preprocesor jest wywoływany w tym kodzie,

  • begin jest zastępowany przez decode(a,n,i,m,a,t,e)
  • decode(a,n,i,m,a,t,e) jest zastępowany przez m ## a ## i ## n
  • m ## a ## i ## n jest zastępowany przez main

W ten sposób skutecznie begin()zastępuje main().

Susam Pal
źródło
8
Nie spodziewałem się tyle przemyśleć, aby nauczyć się zachowania ##, ale myślę, że teraz nigdy tego nie zapomnę? Więc dziękuję.
NicoBerrogorry
2
Zajęło mi to chwilę, aby go śledzić, ale to była fantastyczna odpowiedź na pytanie. Dzięki.
n00dle