2014-02-26 33 views
1

這定義是固定的,我不能改變他們(第三方LIB)

#define X_ERR_OK (0) 
#define X_ERR_FOO (816) 
#define X_ERR_OTHER (842) 
// .. and more 

有一個小功能,它會返回錯誤代碼的名稱(我的代碼,我可以改變它)

#define X_ERR_CASE(e) case e: return #e 
const char* err_name(int err) { 
    switch(err) { 
    X_ERR_CASE(X_ERR_OK); 
    X_ERR_CASE(X_ERR_FOO); 
    X_ERR_CASE(X_ERR_OTHER); 
    } 
    return "<unknown>"; 
} 

這個工程。現在我發現boost.preprocessor智能lib和嘗試使用它:

#define XX_ERR_CASE(r, _, e) case e: return BOOST_PP_STRINGIZE(e); 
#define XX_ERRORS(seq) \ 
    const char* err_name2(int err) { \ 
     switch(err) { \ 
     BOOST_PP_SEQ_FOR_EACH(XX_ERR_CASE, _, seq) \ 
     } \ 
     return "<unknown>"; } 

XX_ERRORS(
    (X_ERR_OK) 
    (X_ERR_FOO) 
    (X_ERR_OTHER) 
) 

但這不工作,因爲輸出不是定義,但數名。例如,我想有:X_ERR_FOO,但我得到(816)

如果我改變XX_ERR_CASE

#define XX_ERR_CASE(r, _, e) case e: return #e; 

我得到BOOST_PP_SEQ_HEAD(((816)) ((842)) (nil))

我如何獲得X_ERR_FOO調用err_name(816)

+2

不幸的是,包含在函數類宏的參數內部的宏在*替換(參數)之前被立即替換*,所以您不能傳遞宏名稱。但是,您可以通過'#'或'##'來禁止擴展。即你#定義E(M)(E,#E)'並用它來創建序列爲E(X_ERR_OK)E(X_ERR_FOO)'等等。 [Live example。](http://coliru.stacked-crooked.com/a/bf245740a9d01bd3) – dyp

+1

http://coliru.stacked-crooked.com/a/6401e0af6b75e700 – llonesmiz

+0

工作!感謝您對dyp和cv_and_he –

回答

1

我懷疑這是可以接受的,但無論如何我會添加它以防萬一。通過這種方法,您需要更改您撥打XX_ERRORS的方式,其參數需要去掉其X_前綴。

#include <iostream> 
#include <boost/preprocessor.hpp> 

#define X_ERR_OK (0) 
#define X_ERR_FOO (816) 
#define X_ERR_OTHER (842) 


#define XX_ERR_CASE(r, _, e) case BOOST_PP_CAT(X_,e): return "X_" BOOST_PP_STRINGIZE(e); 
#define XX_ERRORS(seq) \ 
    const char* err_name2(int err) { \ 
     switch(err) { \ 
     BOOST_PP_SEQ_FOR_EACH(XX_ERR_CASE, _, seq) \ 
     } \ 
     return "<unknown>"; } 

XX_ERRORS(
    (ERR_OK) 
    (ERR_FOO) 
    (ERR_OTHER) 
) 

int main() 
{ 
    std::cout << err_name2(816) << std::endl; 
} 
+0

如果我懷疑這個答案是不可接受的,那就留下評論,我會將其刪除。 – llonesmiz

+0

這是一個非常好的主意。驚人的 - 它的作品! 這不是'不可接受'..我必須考慮,也許有人有另一個答案。 不要刪除它 - 這是一個替代方案。 –