2016-11-17 78 views
0

我想包裝C API函數在某些情況下返回int和其他指向宏,將檢查條件並提供診斷和拋出異常的情況下出現錯誤。對於返回int功能很簡單,因爲我不需要那麼int包裝C API函數返回指針到宏調用

#define CALL_INT(name, ...) do { \ 
     if(!name(__VA_ARGS__)) throw std::runtime_error(#name " failed"); 
    } while(0) 

    // using it 
    CALL_INT(foo, arg); 

但返回指針它不是那麼簡單,因爲我需要檢查指針對nullptr,然後將其分配給我的指針功能。那麼,是否可以編寫類似的宏,所以這個表達式將工作:

auto ptr = CALL_PTR(foobar, arg1, arg2); 

即它會產生代碼,調用foobar(arg1, arg2)檢查結果對nullptr,使之可用於分配的,如果沒有錯誤發生。

+0

爲什麼你這樣做而不是製作模板包裝? – krzaq

+0

@krzaq模板包裝不能串函數名稱 – Slava

+0

只使用宏將函數名稱傳遞給模板包裝的解決方案是否令您滿意? – krzaq

回答

3

真正的解決方案是:不要使用宏。只要寫你想要做的內聯。你和其他人都會在稍後感謝你。


字面的解決辦法是隻立即調用拉姆達:

#define MAYBE_THROW(f, ...)         \ 
    [&]{              \ 
     auto _result = f(__VA_ARGS__);      \ 
     if (!_result) throw std::runtime_error(#f " failed"); \ 
     return _result;          \ 
    }() 

MAYBE_THROW(foo, arg); 
auto ptr = MAYBE_THROW(foobar, arg1, arg2); 
+0

內聯函數的問題 - 每次調用時,我都必須一次又一次地複製粘貼代碼,並解決所有導致的問題。 – Slava

+0

工程!只需要分號需要刪除。爲什麼你在這個lambda中捕獲? – Slava

+0

@Slava將參數傳遞給他們需要捕獲的api函數 – krzaq

1

減神奇的是更好的

#define VERIFY(...) \ 
    [&](){ 
    auto r = __VA_ARGS__; 
    if (!r) throw std::runtime_error(#__VA_ARGS__ " failed"); 
    return r; 
    }() 

這需要一個表達式。它運行它。然後測試它並在失敗時拋出。

如果失敗,它將在throw中包含整個表達式。

然後它返回它。

有更少的魔力,VERIFY(bob)只是在做bob。你可以做

int x = VERIFY(call(a,b,c)); 

VERIFY(y = call(a,b,c)); 

或什麼的。主要代碼運行在那裏;只有斷言包裝失蹤時纔會失效。

VERIFY也被稱爲一般這樣做的宏。