มีวิธีรับพารามิเตอร์เสริมด้วยมาโคร C ++ หรือไม่? การบรรทุกเกินพิกัดก็จะดีเช่นกัน
No you can't
มีวิธีรับพารามิเตอร์เสริมด้วยมาโคร C ++ หรือไม่? การบรรทุกเกินพิกัดก็จะดีเช่นกัน
No you can't
คำตอบ:
นี่เป็นวิธีหนึ่งที่ทำได้ ใช้รายการอาร์กิวเมนต์สองครั้งโดยก่อนอื่นเพื่อสร้างชื่อของมาโครตัวช่วยจากนั้นจึงส่งอาร์กิวเมนต์ไปยังมาโครตัวช่วยนั้น ใช้เคล็ดลับมาตรฐานเพื่อนับจำนวนอาร์กิวเมนต์ให้กับมาโคร
enum
{
plain = 0,
bold = 1,
italic = 2
};
void PrintString(const char* message, int size, int style)
{
}
#define PRINT_STRING_1_ARGS(message) PrintString(message, 0, 0)
#define PRINT_STRING_2_ARGS(message, size) PrintString(message, size, 0)
#define PRINT_STRING_3_ARGS(message, size, style) PrintString(message, size, style)
#define GET_4TH_ARG(arg1, arg2, arg3, arg4, ...) arg4
#define PRINT_STRING_MACRO_CHOOSER(...) \
GET_4TH_ARG(__VA_ARGS__, PRINT_STRING_3_ARGS, \
PRINT_STRING_2_ARGS, PRINT_STRING_1_ARGS, )
#define PRINT_STRING(...) PRINT_STRING_MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__)
int main(int argc, char * const argv[])
{
PRINT_STRING("Hello, World!");
PRINT_STRING("Hello, World!", 18);
PRINT_STRING("Hello, World!", 18, bold);
return 0;
}
สิ่งนี้ทำให้ง่ายขึ้นสำหรับผู้เรียกมาโคร แต่ไม่ใช่ผู้เขียน
PRINT_STRING_MACRO_CHOOSER
จำเป็นยัง? ฉันสามารถแทนที่ด้วยร่างกายภายในโดยตรงและเรียกสิ่งนี้ว่าทั้งหมดได้(__VA_ARGS__)
หรือไม่?
ด้วยความเคารพอย่างสูงต่อ Derek Ledbetter สำหรับคำตอบของเขา - และด้วยความขอโทษที่รื้อฟื้นคำถามเก่า ๆ
ได้รับความเข้าใจในสิ่งที่มันทำและยกขึ้นที่อื่น ๆ ในความสามารถในการ preceed ๆ__VA_ARGS__
กับการ##
อนุญาตให้ฉันจะเกิดขึ้นกับการเปลี่ยนแปลง ...
// The multiple macros that you would need anyway [as per: Crazy Eddie]
#define XXX_0() <code for no arguments>
#define XXX_1(A) <code for one argument>
#define XXX_2(A,B) <code for two arguments>
#define XXX_3(A,B,C) <code for three arguments>
#define XXX_4(A,B,C,D) <code for four arguments>
// The interim macro that simply strips the excess and ends up with the required macro
#define XXX_X(x,A,B,C,D,FUNC, ...) FUNC
// The macro that the programmer uses
#define XXX(...) XXX_X(,##__VA_ARGS__,\
XXX_4(__VA_ARGS__),\
XXX_3(__VA_ARGS__),\
XXX_2(__VA_ARGS__),\
XXX_1(__VA_ARGS__),\
XXX_0(__VA_ARGS__)\
)
สำหรับผู้ที่ไม่ใช่ผู้เชี่ยวชาญเช่นฉันที่สะดุดกับคำตอบ แต่ไม่เห็นว่ามันทำงานอย่างไรฉันจะดำเนินการตามขั้นตอนจริงโดยเริ่มจากรหัสต่อไปนี้ ...
XXX();
XXX(1);
XXX(1,2);
XXX(1,2,3);
XXX(1,2,3,4);
XXX(1,2,3,4,5); // Not actually valid, but included to show the process
กลายเป็น...
XXX_X(, XXX_4(), XXX_3(), XXX_2(), XXX_1(), XXX_0() );
XXX_X(, 1, XXX_4(1), XXX_3(1), XXX_2(1), XXX_1(1), XXX_0(1) );
XXX_X(, 1, 2, XXX_4(1,2), XXX_3(1,2), XXX_2(1,2), XXX_1(1,2), XXX_0(1,2) );
XXX_X(, 1, 2, 3, XXX_4(1,2,3), XXX_3(1,2,3), XXX_2(1,2,3), XXX_1(1,2,3), XXX_0(1,2,3) );
XXX_X(, 1, 2, 3, 4, XXX_4(1,2,3,4), XXX_3(1,2,3,4), XXX_2(1,2,3,4), XXX_1(1,2,3,4), XXX_0(1,2,3,4) );
XXX_X(, 1, 2, 3, 4, 5, XXX_4(1,2,3,4,5), XXX_3(1,2,3,4,5), XXX_2(1,2,3,4,5), XXX_1(1,2,3,4,5), XXX_0(1,2,3,4,5) );
ซึ่งกลายเป็นเพียงข้อโต้แย้งที่หก ...
XXX_0();
XXX_1(1);
XXX_2(1,2);
XXX_3(1,2,3);
XXX_4(1,2,3,4);
5;
PS: ลบ #define สำหรับ XXX_0 เพื่อรับข้อผิดพลาดในการคอมไพล์ [เช่น: ถ้าไม่อนุญาตตัวเลือกไม่มีอาร์กิวเมนต์]
PPS: น่าจะดีที่มีสถานการณ์ที่ไม่ถูกต้อง (เช่น 5) เป็นสิ่งที่ทำให้เกิดข้อผิดพลาดในการคอมไพล์ที่ชัดเจนกว่าสำหรับโปรแกรมเมอร์!
PPPS: ฉันไม่ใช่ผู้เชี่ยวชาญดังนั้นฉันมีความสุขมากที่ได้รับฟังความคิดเห็น (ดีไม่ดีหรืออื่น ๆ )!
XXX_X(,##__VA_ARGS__,` ...
XXX_X (, XXX_4 (), XXX_3 (), XXX_2 (), XXX_1 (), XXX_0 ()); `
มาโคร C ++ ไม่ได้เปลี่ยนจาก C เนื่องจาก C ไม่มีการโอเวอร์โหลดและอาร์กิวเมนต์เริ่มต้นสำหรับฟังก์ชันจึงไม่มีมาโครเหล่านี้อย่างแน่นอน ดังนั้นเพื่อตอบคำถามของคุณ: ไม่คุณลักษณะเหล่านี้ไม่มีอยู่สำหรับมาโคร ทางเลือกเดียวของคุณคือกำหนดมาโครหลายชื่อที่แตกต่างกัน (หรือไม่ใช้มาโครเลย)
ในฐานะที่เป็นแนวทาง: ใน C ++ โดยทั่วไปถือว่าเป็นแนวทางปฏิบัติที่ดีในการย้ายออกจากมาโครให้มากที่สุด หากคุณต้องการคุณสมบัติเช่นนี้มีโอกาสดีที่คุณจะใช้มาโครมากเกินไป
__FILE__
และ__LINE__
และเช่น ...
ด้วยความเคารพอย่างยิ่งต่อDerek Ledbetter , David Sorkovsky , Syphorlateสำหรับคำตอบของพวกเขาพร้อมกับวิธีการอันชาญฉลาดในการตรวจจับอาร์กิวเมนต์มาโครที่ว่างเปล่าโดยJens Gustedtที่
https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/
ในที่สุดฉันก็ออกมาพร้อมกับบางสิ่งบางอย่างที่รวมเอากลเม็ดทั้งหมดไว้เพื่อแก้ปัญหา
, ##__VA_ARGS__
สำหรับ GCC / CLANG และการกลืนโดยนัยโดย##__VA_ARGS__
สำหรับ MSVC) ดังนั้นอย่าลังเลที่จะผ่านสิ่งที่ขาดหายไป--std=c99
ยังคอมไพเลอร์ของคุณหากคุณต้องการ =)ทำงานข้ามแพลตฟอร์มอย่างสมเหตุสมผลอย่างน้อยก็ทดสอบ
สำหรับคนขี้เกียจให้ข้ามไปที่โพสต์สุดท้ายเพื่อคัดลอกแหล่งที่มา ด้านล่างนี้คือคำอธิบายโดยละเอียดซึ่งหวังว่าจะช่วยและสร้างแรงบันดาลใจให้กับทุกคนที่กำลังมองหา__VA_ARGS__
วิธีแก้ปัญหาทั่วไปเช่นฉัน =)
นี่คือวิธีดำเนินการ ครั้งแรกกำหนดผู้ใช้มองเห็นมากเกินไป "ฟังก์ชั่น" ผมตั้งชื่อมันcreate
และความหมายฟังก์ชั่นที่เกิดขึ้นจริงrealCreate
และนิยามแมโครที่มีจำนวนที่แตกต่างกันของการขัดแย้งCREATE_2
, CREATE_1
, CREATE_0
ที่แสดงด้านล่าง:
#define create(...) MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__)
void realCreate(int x, int y)
{
printf("(%d, %d)\n", x, y);
}
#define CREATE_2(x, y) realCreate(x, y)
#define CREATE_1(x) CREATE_2(x, 0)
#define CREATE_0() CREATE_1(0)
MACRO_CHOOSER(__VA_ARGS__)
ส่วนหนึ่งในที่สุดมีมติให้ความหมายของชื่อแมโครและครั้งที่สอง(__VA_ARGS__)
ส่วนประกอบด้วยรายการพารามิเตอร์ของพวกเขา ดังนั้นการเรียกร้องของผู้ใช้เพื่อcreate(10)
แก้ไขไปCREATE_1(10)
ที่CREATE_1
ส่วนหนึ่งมาจากMACRO_CHOOSER(__VA_ARGS__)
และ(10)
ส่วนหนึ่งมาจากการที่สอง(__VA_ARGS__)
ส่วนหนึ่งมาจากการที่สอง
MACRO_CHOOSER
ใช้เคล็ดลับว่าถ้า__VA_ARGS__
ว่างเปล่านิพจน์ต่อไปนี้จะถูกตัดแบ่งเป็นโทรแมโครที่ถูกต้องโดย preprocessor นี้:
NO_ARG_EXPANDER __VA_ARGS__ () // simply shrinks to NO_ARG_EXPANDER()
อย่างชาญฉลาดเราสามารถกำหนดการเรียกมาโครที่เป็นผลลัพธ์นี้เป็น
#define NO_ARG_EXPANDER() ,,CREATE_0
สังเกตเครื่องหมายจุลภาคสองอันจะมีการอธิบายเร็ว ๆ นี้ มาโครที่มีประโยชน์ต่อไปคือ
#define MACRO_CHOOSER(...) CHOOSE_FROM_ARG_COUNT(NO_ARG_EXPANDER __VA_ARGS__ ())
ดังนั้นการโทรของ
create();
create(10);
create(20, 20);
จะขยายเป็น
CHOOSE_FROM_ARG_COUNT(,,CREATE_0)();
CHOOSE_FROM_ARG_COUNT(NO_ARG_EXPANDER 10 ())(10);
CHOOSE_FROM_ARG_COUNT(NO_ARG_EXPANDER 20, 20 ())(20, 20);
ตามที่ชื่อมาโครแนะนำเราจะนับจำนวนอาร์กิวเมนต์ในภายหลัง นี่คือเคล็ดลับอีกประการหนึ่ง: ตัวประมวลผลก่อนทำการเปลี่ยนข้อความธรรมดาเท่านั้น มันอนุมานจำนวนอาร์กิวเมนต์ของการเรียกมาโครจากจำนวนลูกน้ำที่เห็นภายในวงเล็บ "อาร์กิวเมนต์" จริงที่คั่นด้วยเครื่องหมายจุลภาคไม่จำเป็นต้องเป็นไวยากรณ์ที่ถูกต้อง สามารถเป็นข้อความใดก็ได้ กล่าวคือในตัวอย่างข้างต้นNO_ARG_EXPANDER 10 ()
จะนับเป็น 1 อาร์กิวเมนต์สำหรับการเรียกกลาง NO_ARG_EXPANDER 20
และ20 ()
นับเป็น 2 อาร์กิวเมนต์สำหรับการเรียกด้านล่างตามลำดับ
หากเราใช้มาโครตัวช่วยต่อไปนี้เพื่อขยายเพิ่มเติม
##define CHOOSE_FROM_ARG_COUNT(...) \
FUNC_RECOMPOSER((__VA_ARGS__, CREATE_2, CREATE_1, ))
#define FUNC_RECOMPOSER(argsWithParentheses) \
FUNC_CHOOSER argsWithParentheses
ต่อท้าย,
หลังจากที่CREATE_1
มีการทำงานรอบสำหรับ GCC / เสียงดังกราวปราบปราม (การบวกเท็จ) ข้อผิดพลาดบอกว่าISO C99 requires rest arguments to be used
เมื่อผ่าน-pedantic
การคอมไพเลอร์ของคุณ FUNC_RECOMPOSER
เป็นงานรอบสำหรับ MSVC หรือมันไม่สามารถนับจำนวนของอาร์กิวเมนต์ (เช่นจุลภาค) ในวงเล็บของสายแมโครได้อย่างถูกต้อง ผลลัพธ์จะได้รับการแก้ไขต่อไป
FUNC_CHOOSER (,,CREATE_0, CREATE_2, CREATE_1, )();
FUNC_CHOOSER (NO_ARG_EXPANDER 10 (), CREATE_2, CREATE_1, )(10);
FUNC_CHOOSER (NO_ARG_EXPANDER 20, 20 (), CREATE_2, CREATE_1, )(20, 20);
อย่างที่คุณเห็นนกอินทรีขั้นตอนเดียวที่เราต้องการคือใช้เคล็ดลับการนับอาร์กิวเมนต์มาตรฐานเพื่อเลือกชื่อเวอร์ชันมาโครที่ต้องการในที่สุด:
#define FUNC_CHOOSER(_f1, _f2, _f3, ...) _f3
ซึ่งจะแก้ไขผลลัพธ์เป็น
CREATE_0();
CREATE_1(10);
CREATE_2(20, 20);
และให้การเรียกใช้ฟังก์ชันจริงที่ต้องการ:
realCreate(0, 0);
realCreate(10, 10);
realCreate(20, 20);
เมื่อรวมทั้งหมดเข้าด้วยกันด้วยการจัดเรียงคำสั่งใหม่เพื่อให้อ่านง่ายขึ้นแหล่งที่มาทั้งหมดของตัวอย่าง 2 อาร์กิวเมนต์อยู่ที่นี่:
#include <stdio.h>
void realCreate(int x, int y)
{
printf("(%d, %d)\n", x, y);
}
#define CREATE_2(x, y) realCreate(x, y)
#define CREATE_1(x) CREATE_2(x, 0)
#define CREATE_0() CREATE_1(0)
#define FUNC_CHOOSER(_f1, _f2, _f3, ...) _f3
#define FUNC_RECOMPOSER(argsWithParentheses) FUNC_CHOOSER argsWithParentheses
#define CHOOSE_FROM_ARG_COUNT(...) FUNC_RECOMPOSER((__VA_ARGS__, CREATE_2, CREATE_1, ))
#define NO_ARG_EXPANDER() ,,CREATE_0
#define MACRO_CHOOSER(...) CHOOSE_FROM_ARG_COUNT(NO_ARG_EXPANDER __VA_ARGS__ ())
#define create(...) MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__)
int main()
{
create();
create(10);
create(20, 20);
//create(30, 30, 30); // Compilation error
return 0;
}
แม้ว่าผู้พัฒนา API จะซับซ้อนน่าเกลียดและเป็นภาระ แต่ก็มีวิธีแก้ปัญหาสำหรับการโอเวอร์โหลดและการตั้งค่าพารามิเตอร์เสริมของฟังก์ชัน C / C ++ สำหรับพวกเราที่คลั่งไคล้ การใช้งาน API ที่ล้นมือที่กำลังจะมาถึงกลายเป็นเรื่องสนุกและน่าพอใจมาก =)
หากมีความเป็นไปได้เพิ่มเติมสำหรับแนวทางนี้โปรดแจ้งให้เราทราบที่
https://github.com/jason-deng/C99FunctionOverload
ขอขอบคุณเป็นพิเศษอีกครั้งสำหรับผู้คนที่ยอดเยี่ยมทุกคนที่เป็นแรงบันดาลใจและทำให้ฉันทำงานชิ้นนี้ให้สำเร็จ! =)
สำหรับใครก็ตามที่กำลังค้นหาโซลูชัน VA_NARGS ที่ทำงานร่วมกับ Visual C ++ ได้อย่างเจ็บปวด มาโครต่อไปนี้ใช้งานได้อย่างไม่มีที่ติสำหรับฉัน (ยังมีพารามิเตอร์เป็นศูนย์!) ใน Visual c ++ express 2010:
#define VA_NUM_ARGS_IMPL(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,N,...) N
#define VA_NUM_ARGS_IMPL_(tuple) VA_NUM_ARGS_IMPL tuple
#define VA_NARGS(...) bool(#__VA_ARGS__) ? (VA_NUM_ARGS_IMPL_((__VA_ARGS__, 24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1))) : 0
หากคุณต้องการมาโครที่มีพารามิเตอร์เสริมคุณสามารถทำได้:
//macro selection(vc++)
#define SELMACRO_IMPL(_1,_2,_3, N,...) N
#define SELMACRO_IMPL_(tuple) SELMACRO_IMPL tuple
#define mymacro1(var1) var1
#define mymacro2(var1,var2) var2*var1
#define mymacro3(var1,var2,var3) var1*var2*var3
#define mymacro(...) SELMACRO_IMPL_((__VA_ARGS__, mymacro3(__VA_ARGS__), mymacro2(__VA_ARGS__), mymacro1(__VA_ARGS__)))
ที่ได้ผลสำหรับฉันเช่นกันใน vc. แต่ใช้ไม่ได้กับพารามิเตอร์ศูนย์
int x=99;
x=mymacro(2);//2
x=mymacro(2,2);//4
x=mymacro(2,2,2);//8
unresolved external symbol _bool referenced in function _main
gcc
/ g++
รองรับมาโคร varargsแต่ฉันไม่คิดว่านี่เป็นมาตรฐานดังนั้นโปรดใช้ความเสี่ยงเอง
#include <stdio.h>
#define PP_NARG(...) \
PP_NARG_(__VA_ARGS__,PP_RSEQ_N())
#define PP_NARG_(...) \
PP_ARG_N(__VA_ARGS__)
#define PP_ARG_N( \
_1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
_11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
_21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
_31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
_41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
_51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
_61,_62,_63,N,...) N
#define PP_RSEQ_N() \
63,62,61,60, \
59,58,57,56,55,54,53,52,51,50, \
49,48,47,46,45,44,43,42,41,40, \
39,38,37,36,35,34,33,32,31,30, \
29,28,27,26,25,24,23,22,21,20, \
19,18,17,16,15,14,13,12,11,10, \
9,8,7,6,5,4,3,2,1,0
#define PP_CONCAT(a,b) PP_CONCAT_(a,b)
#define PP_CONCAT_(a,b) a ## b
#define THINK(...) PP_CONCAT(THINK_, PP_NARG(__VA_ARGS__))(__VA_ARGS__)
#define THINK_0() THINK_1("sector zz9 plural z alpha")
#define THINK_1(location) THINK_2(location, 42)
#define THINK_2(location,answer) THINK_3(location, answer, "deep thought")
#define THINK_3(location,answer,computer) \
printf ("The answer is %d. This was calculated by %s, and a computer to figure out what this"
" actually means will be build in %s\n", (answer), (computer), (location))
int
main (int argc, char *argv[])
{
THINK (); /* On compilers other than GCC you have to call with least one non-default argument */
}
การปฏิเสธความรับผิด: ส่วนใหญ่ไม่เป็นอันตราย
:%s/MY_MACRO_/THINK_/g
:)
i686-apple-darwin10-g++-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5664)
นั่นไม่ใช่สิ่งที่พรีโปรเซสเซอร์ออกแบบมาสำหรับ
ที่กล่าวว่าถ้าคุณต้องการที่จะใส่ลงไปในพื้นที่อย่างจริงจังที่ท้าทายความสามารถในการเขียนโปรแกรมแมโครที่มีจำนวนเล็กน้อยของการอ่านที่คุณควรจะดูที่การเพิ่มห้องสมุด preprocessor ท้ายที่สุดมันจะไม่เป็น C ++ หากไม่มีระดับการเขียนโปรแกรมที่เข้ากันได้กับทัวริงสามระดับอย่างสมบูรณ์ (ตัวประมวลผลก่อนตัวประมวลผลแม่แบบการเขียนโปรแกรมและระดับพื้นฐาน C ++)!
#define MY_MACRO_3(X,Y,Z) ...
#define MY_MACRO_2(X,Y) MY_MACRO(X,Y,5)
#define MY_MACRO_1(X) MY_MACRO(X,42,5)
คุณจะรู้ว่าคุณจะผ่านไปกี่ args ดังนั้นจึงไม่จำเป็นต้องมีการโอเวอร์โหลด
รหัสของ Derek Ledbetter รุ่นที่กระชับยิ่งขึ้น:
enum
{
plain = 0,
bold = 1,
italic = 2
};
void PrintString(const char* message = NULL, int size = 0, int style = 0)
{
}
#define PRINT_STRING(...) PrintString(__VA_ARGS__)
int main(int argc, char * const argv[])
{
PRINT_STRING("Hello, World!");
PRINT_STRING("Hello, World!", 18);
PRINT_STRING("Hello, World!", 18, bold);
return 0;
}
ในฐานะแฟนตัวยงของสัตว์ประหลาดมาโครที่น่ากลัวฉันต้องการขยายคำตอบของ Jason Deng และทำให้มันใช้งานได้จริง (เพื่อให้ดีขึ้นหรือแย่ลง) ต้นฉบับไม่น่าใช้มากนักเพราะคุณต้องปรับเปลี่ยนตัวอักษรตัวใหญ่ทุกครั้งที่คุณต้องการสร้างมาโครใหม่และจะยิ่งแย่ไปกว่านั้นหากคุณต้องการอาร์กิวเมนต์ที่แตกต่างกัน
ดังนั้นฉันจึงสร้างเวอร์ชันที่มีคุณสมบัติเหล่านี้:
ตอนนี้ฉันสร้างอาร์กิวเมนต์ได้สูงสุด 16 อาร์กิวเมนต์ แต่ถ้าคุณต้องการมากกว่านั้น (ตอนนี้คุณแค่โง่ ... ) คุณสามารถแก้ไข FUNC_CHOOSER และ CHOOSE_FROM_ARG_COUNT จากนั้นเพิ่มเครื่องหมายจุลภาคใน NO_ARG_EXPANDER
โปรดดูคำตอบที่ยอดเยี่ยมของ Jason Deng สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับการใช้งาน แต่ฉันจะใส่รหัสที่นี่:
#include <stdio.h>
void realCreate(int x, int y)
{
printf("(%d, %d)\n", x, y);
}
// This part you put in some library header:
#define FUNC_CHOOSER(_f0, _f1, _f2, _f3, _f4, _f5, _f6, _f7, _f8, _f9, _f10, _f11, _f12, _f13, _f14, _f15, _f16, ...) _f16
#define FUNC_RECOMPOSER(argsWithParentheses) FUNC_CHOOSER argsWithParentheses
#define CHOOSE_FROM_ARG_COUNT(F, ...) FUNC_RECOMPOSER((__VA_ARGS__, \
F##_16, F##_15, F##_14, F##_13, F##_12, F##_11, F##_10, F##_9, F##_8,\
F##_7, F##_6, F##_5, F##_4, F##_3, F##_2, F##_1, ))
#define NO_ARG_EXPANDER(FUNC) ,,,,,,,,,,,,,,,,FUNC ## _0
#define MACRO_CHOOSER(FUNC, ...) CHOOSE_FROM_ARG_COUNT(FUNC, NO_ARG_EXPANDER __VA_ARGS__ (FUNC))
#define MULTI_MACRO(FUNC, ...) MACRO_CHOOSER(FUNC, __VA_ARGS__)(__VA_ARGS__)
// When you need to make a macro with default arguments, use this:
#define create(...) MULTI_MACRO(CREATE, __VA_ARGS__)
#define CREATE_0() CREATE_1(0)
#define CREATE_1(x) CREATE_2(x, 0)
#define CREATE_2(x, y) \
do { \
/* put whatever code you want in the last macro */ \
realCreate(x, y); \
} while(0)
int main()
{
create();
create(10);
create(20, 20);
//create(30, 30, 30); // Compilation error
return 0;
}
คุณสามารถใช้BOOST_PP_OVERLOAD
จากboost
ห้องสมุด
ตัวอย่างจากเอกสารการเพิ่มอย่างเป็นทางการ :
#include <boost/preprocessor/facilities/overload.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/facilities/empty.hpp>
#include <boost/preprocessor/arithmetic/add.hpp>
#define MACRO_1(number) MACRO_2(number,10)
#define MACRO_2(number1,number2) BOOST_PP_ADD(number1,number2)
#if !BOOST_PP_VARIADICS_MSVC
#define MACRO_ADD_NUMBERS(...) BOOST_PP_OVERLOAD(MACRO_,__VA_ARGS__)(__VA_ARGS__)
#else
// or for Visual C++
#define MACRO_ADD_NUMBERS(...) \
BOOST_PP_CAT(BOOST_PP_OVERLOAD(MACRO_,__VA_ARGS__)(__VA_ARGS__),BOOST_PP_EMPTY())
#endif
MACRO_ADD_NUMBERS(5) // output is 15
MACRO_ADD_NUMBERS(3,6) // output is 9
ขึ้นอยู่กับสิ่งที่คุณต้องการคุณสามารถทำได้ด้วยvar argsด้วยมาโคร ตอนนี้พารามิเตอร์ที่เป็นทางเลือกหรือการโอเวอร์โหลดมาโครไม่มีสิ่งนั้น
ไม่มีตัวอย่างข้างต้น (จาก Derek Ledbetter, David Sorkovsky และ Joe D) ที่จะนับอาร์กิวเมนต์ด้วยมาโครที่ใช้งานได้สำหรับฉันโดยใช้ Microsoft VCC 10 __VA_ARGS__
อาร์กิวเมนต์นี้ถือเป็นอาร์กิวเมนต์เดียวเสมอ (โทเค็น - เพิ่มขนาดด้วย##
or not) ดังนั้น อาร์กิวเมนต์ที่เปลี่ยนไปซึ่งตัวอย่างเหล่านั้นใช้ไม่ได้ผล
ดังนั้นคำตอบสั้น ๆ ตามที่ระบุไว้ข้างต้น: ไม่คุณไม่สามารถโอเวอร์โหลดมาโครหรือใช้อาร์กิวเมนต์ที่เป็นทางเลือกได้