Apa yang dilakukan ## (hash ganda) dalam arahan preprocessor?

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

Baris di atas diambil dari Unreal 4, dan saya tahu saya bisa menanyakannya di forum yang tidak nyata, tapi saya pikir ini adalah pertanyaan C ++ umum yang perlu ditanyakan di sini.

Saya mengerti baris pertama mendefinisikan makro, namun saya tidak berpengalaman dalam preprocessor shenanigans di C ++ dan jadi saya tersesat di sana. Logika memberitahu saya bahwa garis miring terbalik berarti deklarasi berlanjut ke baris berikutnya.

FThreadSafeStaticStat terlihat seperti template, tetapi ada # yang terjadi di sana dan sintaks yang belum pernah saya lihat sebelumnya di C ++

Bisakah seseorang memberi tahu saya apa artinya ini? Saya memahami bahwa Anda mungkin tidak memiliki akses ke Unreal 4, tetapi itu hanya sintaks yang saya tidak mengerti.

DavidColson
sumber
6
Anda dapat membaca tentang ## operator di cppreference , antara lain
Cubbi
1
##adalah / bisa disebut operator penggabungan.
dyp
1
Oh, itu sangat keren! Ini menjelaskan cukup banyak, terima kasih. Tetapi mengapa kata kunci struct digunakan? Garis lebih terlihat seperti definisi variabel
DavidColson
1
Ini structmemperkenalkan penentu tipe yang rumit sejauh yang saya tahu.
dyp
2
Nama resminya adalah "operator penempelan token" karena ini menggabungkan dua token yang diproses sebelumnya untuk menghasilkan yang lain. Perhatikan bahwa itu hanya berlaku jika hasilnya adalah tanda preprocessing valid, misalnya Anda tidak dapat melakukan + ## 3untuk membuat +3. (Tapi + 3tentu saja Anda dapat melakukannya , tanpa operator)
MM

Jawaban:

175

## adalah operator preprocessor untuk penggabungan.

Jadi jika Anda menggunakan

DEFINE_STAT(foo)

di mana saja dalam kode, itu akan diganti dengan

struct FThreadSafeStaticStat<FStat_foo> StatPtr_foo;

sebelum kode Anda dikompilasi.

Berikut adalah contoh lain dari posting blog saya untuk menjelaskan ini lebih lanjut.

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

Program ini akan berhasil dikompilasi dan dijalankan, dan menghasilkan keluaran sebagai berikut:

Stumped?

Ketika preprocessor dipanggil pada kode ini,

  • begin diganti dengan decode(a,n,i,m,a,t,e)
  • decode(a,n,i,m,a,t,e) diganti dengan m ## a ## i ## n
  • m ## a ## i ## n diganti dengan main

Jadi secara efektif, begin()diganti dengan main().

Susam Pal
sumber
8
Saya tidak berharap untuk berpikir banyak untuk mempelajari perilaku ##, tetapi saya kira sekarang saya tidak akan pernah melupakannya? Jadi terima kasih.
NicoBerrogorry
2
Butuh beberapa saat untuk mengikutinya, tetapi ini adalah jawaban yang fantastis untuk pertanyaan itu. Terima kasih.
n00dle