可變參數宏的展開,宏重載


因某些方面需要,涉及到可變參數宏的展開及可變參數數量的確定,在網上查找了大部分資料,基本如下所述

http://www.cnblogs.com/goooon/p/5642514.html

涉及到的問題點:不支持0個參數

經過VS2010及gcc version 4.9.1 (GCC)兩個編譯器編譯,可以至少支持此兩種編譯器下的0參數問題。

以上文中的代碼為例:

定義部分

#define PRIVATE_ARGS_GLUE(x, y) x y

#define PRIVATE_MACRO_VAR_ARGS_IMPL_COUNT(_1,_2,_3,_4,_5,_6,_7,_8,_9, _10, N, ...) N
#define PRIVATE_MACRO_VAR_ARGS_IMPL(args) PRIVATE_MACRO_VAR_ARGS_IMPL_COUNT args
#define COUNT_MACRO_VAR_ARGS(...) PRIVATE_MACRO_VAR_ARGS_IMPL((__VA_ARGS__,10, 9,8,7,6,5,4,3,2,1,0))

#define PRIVATE_MACRO_CHOOSE_HELPER2(M,count)  M##count
#define PRIVATE_MACRO_CHOOSE_HELPER1(M,count) PRIVATE_MACRO_CHOOSE_HELPER2(M,count)
#define PRIVATE_MACRO_CHOOSE_HELPER(M,count)   PRIVATE_MACRO_CHOOSE_HELPER1(M,count)

#define INVOKE_VAR_MACRO(M,...) PRIVATE_ARGS_GLUE(PRIVATE_MACRO_CHOOSE_HELPER(M,COUNT_MACRO_VAR_ARGS(__VA_ARGS__)), (__VA_ARGS__))

實現部分

#define PRINT_ARGS1(a1) std::cout<<a1<<std::endl
#define PRINT_ARGS2(a1,a2) std::cout<<a1<<","<<a2<<std::endl
#define PRINT_ARGS3(a1,a2,a3) std::cout<<a1<<","<<a2<<","<<a3<<std::endl
#define PRINT_ARGS4(a1,a2,a3,a4) std::cout<<a1<<","<<a2<<","<<a3<<","<<a4<<std::endl

使用部分

INVOKE_VAR_MACRO(PRINT_ARGS, 4);
INVOKE_VAR_MACRO(PRINT_ARGS, 4, 5);
INVOKE_VAR_MACRO(PRINT_ARGS, 4, 5, 6);

 

如何實現?

#define PRINT_ARGS0() std::cout<<"ARGS0"<<std::endl

如何使用?

INVOKE_VAR_MACRO(PRINT_ARGS);

參考  http://en.cppreference.com/w/cpp/preprocessor/replace

some compilers offer an extension that allows ## to appear after a comma and before __VA_ARGS__,

in which case the ## does nothing when __VA_ARGS__ is non-empty,

but removes the comma when __VA_ARGS__ is empty: this makes it possible to define macros such as fprintf (stderr, format, ##__VA_ARGS__)

看不懂?那看看http://blog.csdn.net/sakaue/article/details/29591631

 

那是不是可以改成這樣呢?

#define PRIVATE_MACRO_VAR_ARGS_IMPL_COUNT(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9, _10, N, ...) N
#define PRIVATE_MACRO_VAR_ARGS_IMPL(args) PRIVATE_MACRO_VAR_ARGS_IMPL_COUNT args
#define COUNT_MACRO_VAR_ARGS(...) PRIVATE_MACRO_VAR_ARGS_IMPL((0,##__VA_ARGS__,10, 9,8,7,6,5,4,3,2,1,0))

在gcc version 4.9.1 (GCC)下是沒有問題的,

可以輸出

ARGS0
4
4,5
4,5,6

但是在vs2010中就出現了編譯錯誤

warning C4003: “PRINT_ARGS1”宏的實參不足
error C2059: 語法錯誤:“<<”

那是不是意味着vs2010不支持 如果可變參數被忽略或為空,‘##’操作將使預處理器(preprocessor)去除掉它前面的那個逗號。

在vs2010中定義

#define debug(format, ...) fprintf (stderr, format, ##__VA_ARGS__)

vs2010中實現

debug("abc");

結果編譯沒有問題,輸出也正常。

 

因此,應該是vs2010和gcc在預編譯中,對於宏的處理存在差異。最明顯的一個例子就是參考google chromium中logging,

typedef int LogSeverity;
const LogSeverity LOG_VERBOSE = -1;  // This is level 1 verbosity
// Note: the log severities are used to index into the array of names,
// see log_severity_names.
const LogSeverity LOG_INFO = 0;
const LogSeverity LOG_WARNING = 1;
const LogSeverity LOG_ERROR = 2;
const LogSeverity LOG_FATAL = 3;

 

LOG(INFO) << "Found " << num_cookies << " cookies";

其中涉及使用 ::logging::LOG_ ## severity  組成一個 ::logging::LOG_INFO

個人修改時,添加了一個LOG_DEBUG,結果vs2010上編譯使用都沒有問題,gcc version 4.9.1 (GCC)下編譯不過,說找不到LOG_1,修改為LOG_DEBUGGING,編譯及輸出均OK。

 

那么如何在此兩種編譯環境下解決不支持0個參數問題呢?

 

測試代碼

#define PP_ARG_N(_1,_2,_3,_4,_5,_6,_7,_8,_9, _10, N, ...) ((#_1 == "") ? 0 : N)
#define PP_NARG_(args)  PP_ARG_N args
#define PP_NARG(...) PP_NARG_((__VA_ARGS__,10,9,8,7,6,5,4,3,2,1,0))

#define TESTINVOKE_VAR_MACRO(M,...) std::cout<<PP_NARG(__VA_ARGS__)<<std::endl

TESTINVOKE_VAR_MACRO(PRINT_ARGS);
TESTINVOKE_VAR_MACRO(PRINT_ARGS, 4);
TESTINVOKE_VAR_MACRO(PRINT_ARGS, 4, 5);
TESTINVOKE_VAR_MACRO(PRINT_ARGS, 4, 5, 6);

輸出

0
1
2
3

 

但要針對#define PRIVATE_MACRO_VAR_ARGS_IMPL_COUNT(_1,_2,_3,_4,_5,_6,_7,_8,_9, _10, N, ...) N 的修改,那就要需要慢慢修改,為什么呢?

參考宏替換規則,如果將N改為一個表達式,那還能找到對應的 PRINT_ARGSX 嗎?顯然是不能的。但如果作為函數傳參,這個方法還是能夠勝任的,比如上述的測試代碼。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM