Created
September 17, 2014 00:17
-
-
Save thwarted/8ce47e1897a578f4e80a to your computer and use it in GitHub Desktop.
a FOR_EACH C Preprocessor macro that works under both GNU CC and Visual Studio 2013/MSVC
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* all this verbosity is required for this to work reliably and predictably | |
* on both GCC and MSVC | |
*/ | |
/* because gcc cpp doesn't recursively expand macros, so a single CALLIT | |
* macro can't be used in all the FE_n macros below | |
*/ | |
#define FE_CALLITn01(a,b) a b | |
#define FE_CALLITn02(a,b) a b | |
#define FE_CALLITn03(a,b) a b | |
#define FE_CALLITn04(a,b) a b | |
#define FE_CALLITn04(a,b) a b | |
#define FE_CALLITn05(a,b) a b | |
#define FE_CALLITn06(a,b) a b | |
#define FE_CALLITn07(a,b) a b | |
#define FE_CALLITn08(a,b) a b | |
#define FE_CALLITn09(a,b) a b | |
#define FE_CALLITn10(a,b) a b | |
#define FE_CALLITn11(a,b) a b | |
#define FE_CALLITn12(a,b) a b | |
#define FE_CALLITn13(a,b) a b | |
#define FE_CALLITn14(a,b) a b | |
#define FE_CALLITn15(a,b) a b | |
#define FE_CALLITn16(a,b) a b | |
#define FE_CALLITn17(a,b) a b | |
#define FE_CALLITn18(a,b) a b | |
#define FE_CALLITn19(a,b) a b | |
#define FE_CALLITn20(a,b) a b | |
#define FE_CALLITn21(a,b) a b | |
/* the MSVC preprocessor expands __VA_ARGS__ as a single argument, so it needs | |
* to be expanded indirectly through the CALLIT macros. | |
* http://connect.microsoft.com/VisualStudio/feedback/details/380090/variadic-macro-replacement | |
* http://stackoverflow.com/questions/21869917/visual-studio-va-args-issue | |
*/ | |
#define FE_n00() | |
#define FE_n01(what, a, ...) what(a) | |
#define FE_n02(what, a, ...) what(a) FE_CALLITn02(FE_n01,(what, ##__VA_ARGS__)) | |
#define FE_n03(what, a, ...) what(a) FE_CALLITn03(FE_n02,(what, ##__VA_ARGS__)) | |
#define FE_n04(what, a, ...) what(a) FE_CALLITn04(FE_n03,(what, ##__VA_ARGS__)) | |
#define FE_n05(what, a, ...) what(a) FE_CALLITn05(FE_n04,(what, ##__VA_ARGS__)) | |
#define FE_n06(what, a, ...) what(a) FE_CALLITn06(FE_n05,(what, ##__VA_ARGS__)) | |
#define FE_n07(what, a, ...) what(a) FE_CALLITn07(FE_n06,(what, ##__VA_ARGS__)) | |
#define FE_n08(what, a, ...) what(a) FE_CALLITn08(FE_n07,(what, ##__VA_ARGS__)) | |
#define FE_n09(what, a, ...) what(a) FE_CALLITn09(FE_n08,(what, ##__VA_ARGS__)) | |
#define FE_n10(what, a, ...) what(a) FE_CALLITn10(FE_n09,(what, ##__VA_ARGS__)) | |
#define FE_n11(what, a, ...) what(a) FE_CALLITn11(FE_n10,(what, ##__VA_ARGS__)) | |
#define FE_n12(what, a, ...) what(a) FE_CALLITn12(FE_n11,(what, ##__VA_ARGS__)) | |
#define FE_n13(what, a, ...) what(a) FE_CALLITn13(FE_n12,(what, ##__VA_ARGS__)) | |
#define FE_n14(what, a, ...) what(a) FE_CALLITn14(FE_n13,(what, ##__VA_ARGS__)) | |
#define FE_n15(what, a, ...) what(a) FE_CALLITn15(FE_n14,(what, ##__VA_ARGS__)) | |
#define FE_n16(what, a, ...) what(a) FE_CALLITn16(FE_n15,(what, ##__VA_ARGS__)) | |
#define FE_n17(what, a, ...) what(a) FE_CALLITn17(FE_n16,(what, ##__VA_ARGS__)) | |
#define FE_n18(what, a, ...) what(a) FE_CALLITn18(FE_n17,(what, ##__VA_ARGS__)) | |
#define FE_n19(what, a, ...) what(a) FE_CALLITn19(FE_n18,(what, ##__VA_ARGS__)) | |
#define FE_n20(what, a, ...) what(a) FE_CALLITn20(FE_n19,(what, ##__VA_ARGS__)) | |
#define FE_n21(what, a, ...) what(a) FE_CALLITn21(FE_n20,(what, ##__VA_ARGS__)) | |
#define FE_n22(...) ERROR: FOR_EACH only supports up to 21 arguments | |
#define FE_GET_MACRO(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,NAME,...) NAME | |
#define FOR_EACH(what, ...) FE_CALLITn01(FE_GET_MACRO(_0, ##__VA_ARGS__,FE_n22,FE_n21,FE_n20,FE_n19, \ | |
FE_n18,FE_n17,FE_n16,FE_n15,FE_n14,FE_n13,FE_n12,FE_n11,FE_n10,FE_n09,\ | |
FE_n08,FE_n07,FE_n06,FE_n05,FE_n04,FE_n03,FE_n02,FE_n01,FE_n00), (what, ##__VA_ARGS__)) | |
/* Test expansions | |
* Run as: | |
* cpp -D__TEST__ | |
* and examine the output | |
*/ | |
#ifdef __TEST__ | |
Each pair of lines should match. | |
1: FOR_EACH(e1, one) | |
1: e1(one) | |
2: FOR_EACH(e1, one, two) | |
2: e1(one) e1(two) | |
3: FOR_EACH(e1, one, two, three) | |
3: e1(one) e1(two) e1(three) | |
4: FOR_EACH(e1, one, two, three, four) | |
4: e1(one) e1(two) e1(three) e1(four) | |
5: FOR_EACH(e1, one, two, three, four, five) | |
5: e1(one) e1(two) e1(three) e1(four) e1(five) | |
6: FOR_EACH(e1, one, two, three, four, five, six) | |
6: e1(one) e1(two) e1(three) e1(four) e1(five) e1(six) | |
7: FOR_EACH(e1, one, two, three, four, five, six, seven) | |
7: e1(one) e1(two) e1(three) e1(four) e1(five) e1(six) e1(seven) | |
8: FOR_EACH(e1, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) | |
8: e1(a1) e1(a2) e1(a3) e1(a4) e1(a5) e1(a6) e1(a7) e1(a8) e1(a9) e1(a10) e1(a11) e1(a12) e1(a13) e1(a14) e1(a15) e1(a16) e1(a17) e1(a18) e1(a19) e1(a20) | |
9: FOR_EACH(e1, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21) | |
9: e1(a1) e1(a2) e1(a3) e1(a4) e1(a5) e1(a6) e1(a7) e1(a8) e1(a9) e1(a10) e1(a11) e1(a12) e1(a13) e1(a14) e1(a15) e1(a16) e1(a17) e1(a18) e1(a19) e1(a20) e1(a21) | |
a: FOR_EACH(e1, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22) | |
a: ERROR: FOR_EACH only supports up to 21 arguments | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
great work! thanks for sharing this 👍