2017-10-17 109 views
1

Overloading Macro on Number of Arguments爲什麼我的可變參數宏不能正確接受參數?

https://codecraft.co/2014/11/25/variadic-macros-tricks/

我一直在尋找上述兩個環節,試圖讓下面的代碼工作:

#define _GET_NUMBER(_0, _1, _2, _3, _4, _5, NAME, ...) NAME 
#define OUTPUT_ARGS_COUNT(...) _GET_NUMBER(_0, ##__VA_ARGS__, 5, 4, 3, 2, 1, 0) 

... 

cout << OUTPUT_ARGS_COUNT("HelloWorld", 1.2) << endl; 
cout << OUTPUT_ARGS_COUNT("HelloWorld") << endl; 
cout << OUTPUT_ARGS_COUNT() << endl; 

這將編譯,運行,並給出了下面的輸出:

2 
1 
1 

我不能爲我的生活找出爲什麼打電話OUTPUT_ARGS_COUNT()我我給了我1而不是0.我對我正在嘗試使用的代碼有一個很好的理解,但對我來說這仍然是一種希望。所以我猜這可能是我沒有正確應用某些東西,儘管我從字面上複製並從堆棧溢出鏈接粘貼示例代碼。

我用G ++ 5.4.0 20160609.

任何意見或其他資源你可以點我編譯到將不勝感激。

+1

你可以看到http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html:*「上面的解釋是含糊不清的,唯一的宏參數是一個可變參數參數的情況下,因爲它沒有意義來區分是否沒有論證是一個空的論證還是缺少的論證,CPP在符合特定的C標準時保留逗號,否則逗號將作爲標準的擴展刪除。 – Jarod42

+0

選中此https://stackoverflow.com/questions/2308243/macro-returning-the-number-of-arguments-it-is-given-in-c,該解決方案也有失敗的零個參數 –

回答

1

C標準規定

如果標識符列表中的宏定義不與省略號結束,[...]。否則,應當有更多的參數在所述調用以外還有宏定義參數(不包括...)

C2011 6.10.3/4;強調)

C++ 11包含在第16.3/4段中也有同樣的效果。

在這兩種情況下,那麼,如果您的宏調用被解釋爲具有零個參數那麼你的程序是不符合要求的。另一方面,預處理器確實支持空的宏參數 - 即由零預處理標記組成的參數。那麼原則上,在沒有論證和單一的空論證之間存在一個模棱兩可的問題,但實際上,只有後者的解釋導致了一致的程序。

使得G ++選擇採用後者解釋(對方的回答引用它的文檔類似的效果)因此是合理和適當的,但如果你想你的代碼是便攜式的它是不是安全依靠它。採用替代解釋的編譯器行爲會有所不同,可能通過提供您期望的行爲,但也可能通過拒絕代碼。

2

你可以看到http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html

其次,放置一個逗號和變量參數之間時,「##」標誌貼運營商有着特殊的意義。如果你寫

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

和可變參數被冷落使用EPRINTF宏時,則逗號之前的「##」將被刪除。如果您傳遞一個空參數,則不會發生這種情況,如果前面的'##'之前的標記不是逗號,也不會發生這種情況。

eprintf ("success!\n") 
→ fprintf(stderr, "success!\n"); 

以上的說明是不明確的關於其中唯一的宏參數是一個可變參數的參數的情況下,因爲它是沒有意義的,試圖區分完全沒有參數是否是一個空的參數或缺少論據。符合特定C標準時,CPP保留逗號。否則,逗號將作爲標準的擴展而丟棄。

因此,(除非使用適當的擴展名)OUTPUT_ARGS_COUNT()被計爲1個空參數(逗號與##__VA_ARGS__保留)。

+0

我看到的文檔在你對我原來的帖子發表評論之後,但我不知道要修改它,所以我可以在調用OUTPUT_ARGS_COUNT()時得到0。你認爲這是不可能的嗎?或者我可能只是不理解你所指的適當的擴展名。 – Brian

+1

正如你可以在[演示]見(http://coliru.stacked-crooked.com/a/090b4438717735c3),'-std = GNU ++ XX'給出'0'而'-std = C++ XX '給出'1'。你甚至對這個構造有明確的警告。 – Jarod42

+1

@Brian:如引用中所述,它取決於您正在編譯的std版本。如果你用'-std = c99'編譯,你會得到你顯示的輸出。另一方面,如果你使用'-std = gnu99',你會得到'2 1 0'。 –

相關問題