2017-04-16 60 views
0

在C++中,可變宏宏require at least one argument for the '...'。考慮以下功能:FOO(a, b, ...);如果我希望這兩個調用都是正確且無警告的,我應該怎麼做? FOO(5, 4, "gamma"); FOO(5, 4);我正在使用--pedantic標誌,所以只是禁止警告不是一個選項。Variadic宏警告

第二個給出了上面提到的編譯時警告。我認爲這是:

將定義更改爲FOO(a, ...);並將__VA_ARGS__變量(其代表...)拆分爲b,如果存在,則將其分解成其餘部分。所以函數調用看起來像這樣:FOO(5, "4gamma");FOO(5, "4");這,我認爲,這不是一個好的選擇,因爲分割效率不高,函數聲明不需要b參數,即使它是強制性的。

有沒有更好的方法來獲得免警告編譯?

+3

爲什麼使用宏?你試圖解決的實際問題是什麼? –

+0

可變參數函數模板是您的解決方案。 – DeiDei

+0

@DeiDei請你詳細說明功能模板? – FigsHigs

回答

3

儘管我完全同意,如果可能的話,應該使用可變參數函數或函數模板,這個問題也顯示出一些關於宏可以和不可以做什麼的誤解,所以在這個答案中,我將假裝函數不是一種選擇。

改變定義FOO(a, ...);__VA_ARGS__變量(其代表...)分成b和,如果存在的話,進入休息。

是的。

所以函數調用看起來像:FOO(5, "4gamma");FOO(5, "4");

號繼續調用爲FOO(5, 4, "gamma");FOO(5, 4);。在第一種情況下,__VA_ARGS__4, "gamma"。在第二種情況下,__VA_ARGS__4

如果您需要從前者提取, "gamma",那麼可以由預處理器完成。它需要參數數量的上限,但您可以將其增加到幾乎任何您喜歡的數字。雖然這很醜陋。

如果__VA_ARGS__不包含逗號,提取很簡單:

#define COMMA_TRAILING_ARGS_0(a) 

如果你知道__VA_ARGS__至少包含一個逗號,你可以使用

#define COMMA_TRAILING_ARGS_1(a, ...) , __VA_ARGS__ 

而且你可以檢測到這些來使用,達到一定的宏參數上限:

#define ARG16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, ...) _16 
#define HAS_COMMA(...) ARG16(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,) 

合併:

#define COMMA_TRAILING_ARGS_0(a) 
#define COMMA_TRAILING_ARGS_1(a, ...) , __VA_ARGS__ 

#define ARG16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, ...) _16 
#define HAS_COMMA(...) ARG16(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,) 

#define CONCAT(a, b) a ## b 
#define CONCAT_(a, b) CONCAT(a, b) 

#define FOO(a, ...) BAR(a CONCAT_(COMMA_TRAILING_ARGS_, HAS_COMMA(__VA_ARGS__)) (__VA_ARGS__)) 

FOO(5, 4, x, q); // expands to BAR(5, x, q); 
FOO(5, 4, "gamma"); // expands to BAR(5, "gamma"); 
FOO(5, 4);   // expands to BAR(5); 
2
  • 你就可以擺脫這個宏,因爲宏是邪惡的,與模板或別的東西代替它
  • 可以定義兩個宏:FOOs - 有許多爭論和FOO - 只有兩個變元的
  • 你可以使用gcc ##__VA_ARGS__ extension(假設你正在使用gcc或兼容的編譯器)
+0

但這意味着我將不得不'FOO(5,4); FOOs(5,4,「gamma」);',這與我想要的稍有不同。 – FigsHigs

1

我不明白你的具體問題,但你已經證明什麼,它更容易使用兩個重載函數。

void foo(int, int); 
void foo(int, int, const std::string&); 

foo(3, 4); // calls first 
foo(3, 4, "hello"); // calls second 

或甚至:

void foo(int, int, const std::string& = ""); 

在另一方面,如果你可以使用C++ 11:

template<typename... Args> 
void foo(int, int, const Args&... args); // google variadic templates 

的參數組(args)可以由零或更多參數。