## (แฮชคู่) ทำอะไรในคำสั่งพรีโปรเซสเซอร์


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

บรรทัดด้านบนมาจาก Unreal 4 และฉันรู้ว่าฉันสามารถถามมันได้ในฟอรัมที่ไม่จริง แต่ฉันคิดว่านี่เป็นคำถาม C ++ ทั่วไปที่รับประกันว่าถูกถามที่นี่

ฉันเข้าใจว่าบรรทัดแรกกำหนดมาโคร แต่ฉันไม่ชำนาญในเชนานิแกนของตัวประมวลผลล่วงหน้าใน C ++ ดังนั้นฉันจึงหลงทางตรงนั้น ตรรกะบอกฉันว่าแบ็กสแลชหมายความว่าการประกาศจะดำเนินต่อไปในบรรทัดถัดไป

FThreadSafeStaticStat ดูเหมือนเทมเพลต แต่มี # เกิดขึ้นที่นั่นและไวยากรณ์ที่ฉันไม่เคยเห็นมาก่อนใน C ++

มีใครบอกฉันได้ไหมว่านี่หมายถึงอะไร ฉันเข้าใจว่าคุณอาจไม่มีสิทธิ์เข้าถึง Unreal 4 แต่เป็นเพียงไวยากรณ์ที่ฉันไม่เข้าใจ


7
คุณสามารถอ่านเกี่ยวกับตัวดำเนินการ ## บน cppreferenceและอื่น ๆ อีกมากมาย
Cubbi

1
##คือ / อาจเรียกได้ว่าเป็นตัวดำเนินการเชื่อมต่อ
dyp

1
โอ้โหเจ๋งมาก! มันอธิบายได้ค่อนข้างมากขอบคุณ แต่ทำไมถึงใช้คำหลัก struct? บรรทัดดูเหมือนนิยามตัวแปรมากขึ้น
DavidColson

1
structแนะนำประเภทระบุซับซ้อนเท่าที่ผมสามารถบอกได้
dyp

2
ชื่ออย่างเป็นทางการคือ "ตัวดำเนินการวางโทเค็น" เนื่องจากรวมโทเค็นการประมวลผลล่วงหน้าสองรายการเพื่อสร้างอีกรายการหนึ่ง หมายเหตุว่ามันจะใช้ได้เฉพาะถ้าผลที่ได้คือก่อนการประมวลผลที่ถูกต้อง token เช่นคุณไม่สามารถทำเพื่อให้+ ## 3 +3(แต่คุณสามารถทำได้+ 3โดยไม่ต้องใช้ตัวดำเนินการ)
MM

คำตอบ:


180

## เป็นตัวดำเนินการก่อนโปรเซสเซอร์สำหรับการเชื่อมต่อ

ดังนั้นถ้าคุณใช้

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()


9
ฉันไม่ได้คาดหวังว่าจะคิดมากเพื่อเรียนรู้พฤติกรรมของ ## แต่ฉันเดาว่าตอนนี้ฉันจะไม่มีวันลืมมัน? ขอบคุณมาก
NicoBerrogorry

2
ใช้เวลาติดตามสักครู่ แต่นี่เป็นคำตอบที่ยอดเยี่ยมสำหรับคำถามนี้ ขอบคุณ.
n00dle

1

TLDR; ##มีไว้สำหรับการเรียงต่อกันและใช้#สำหรับการทำให้เป็นสตริง (จากcppreference )

##เชื่อมตัวระบุเนื่องและจะเป็นประโยชน์เมื่อคุณต้องการที่จะผ่านฟังก์ชั่นเป็นพารามิเตอร์ นี่คือตัวอย่างที่fooยอมรับอาร์กิวเมนต์ของฟังก์ชันเป็นอาร์กิวเมนต์ที่ 1 และตัวดำเนินการaและbเป็นอาร์กิวเมนต์ที่ 2 และ 3:

#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;
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.