นี่คือ gotcha ที่ฉันพบเมื่ออัปเกรดเป็นคอมไพเลอร์เวอร์ชันใหม่:
การใช้ตัวดำเนินการวางโทเค็นโดยไม่จำเป็น ( ##
) ไม่สามารถพกพาได้และอาจทำให้เกิดช่องว่างคำเตือนหรือข้อผิดพลาดที่ไม่ต้องการ
เมื่อผลลัพธ์ของตัวดำเนินการวางโทเค็นไม่ใช่โทเค็นตัวประมวลผลล่วงหน้าที่ถูกต้องตัวดำเนินการวางโทเค็นก็ไม่จำเป็นและอาจเป็นอันตรายได้
ตัวอย่างเช่นอาจพยายามสร้างตัวอักษรสตริงในเวลาคอมไพล์โดยใช้ตัวดำเนินการวางโทเค็น:
#define STRINGIFY(x) #x
#define PLUS(a, b) STRINGIFY(a##+##b)
#define NS(a, b) STRINGIFY(a##::##b)
printf("%s %s\n", PLUS(1,2), NS(std,vector));
ในคอมไพเลอร์บางตัวสิ่งนี้จะให้ผลลัพธ์ที่คาดหวัง:
1+2 std::vector
ในคอมไพเลอร์อื่น ๆ จะรวมถึงช่องว่างที่ไม่ต้องการ:
1 + 2 std :: vector
GCC เวอร์ชันที่ทันสมัยพอสมควร (> = 3.3 หรือมากกว่านั้น) จะไม่สามารถรวบรวมรหัสนี้ได้:
foo.cpp:16:1: pasting "1" and "+" does not give a valid preprocessing token
foo.cpp:16:1: pasting "+" and "2" does not give a valid preprocessing token
foo.cpp:16:1: pasting "std" and "::" does not give a valid preprocessing token
foo.cpp:16:1: pasting "::" and "vector" does not give a valid preprocessing token
วิธีแก้ปัญหาคือการละเว้นตัวดำเนินการวางโทเค็นเมื่อเชื่อมต่อโทเค็นตัวประมวลผลล่วงหน้ากับตัวดำเนินการ C / C ++
#define STRINGIFY(x) #x
#define PLUS(a, b) STRINGIFY(a+b)
#define NS(a, b) STRINGIFY(a::b)
printf("%s %s\n", PLUS(1,2), NS(std,vector));
เอกสารบท GCC CPP ในการเรียงต่อกันมีข้อมูลที่เป็นประโยชน์เพิ่มเติมเกี่ยวกับผู้ประกอบการ token-วาง
std::wstring BuildDate = WIDEN(__DATE__) L" " WIDEN(__TIME__);
และสร้างสตริงทั้งหมดพร้อมกันโดยปริยาย