2017-01-27 211 views
2

我使用的是(C)庫函數採取不同的參數,但總是在錯誤的情況下返回大於零的int:是否有可能proxify任何功能

int functionA(int param1, char param2); /* return an error code on failure, 0 otherwise */ 
int functionB(LIB_BOOLEAN param1);  /* return an error code on failure, 0 otherwise */ 
// ... 

我想他們都轉向準備好例外:

if (functionA(param1, param2) > 0) 
{ throw std::runtime_error("Method failed"); } 

是否有可能爲所有方法編寫一次模板?

編輯: 這個想法是爲了避免每次使用它時檢查每個函數的結果。

+0

你爲什麼要這麼做? 'assert()'有什麼問題?更好:單元測試。 – tadman

+0

你當然可以通過預處理器宏來做到這一點。 –

+0

* poxify *是什麼意思? – Barmar

回答

5

你的意思是這樣的嗎?

template<typename F, typename... Args> 
auto my_invoke(F &&f, Args&&... args) { 
    if(std::forward<F>(f)(std::forward<Args>(args)...)) { 
     throw std::runtime_error("Method failed"); 
    } 
} 

你可以稱之爲;

my_invoke(functionA, 0, 'c'); 
+1

自從我沒有做C++以來已經有相當一段時間了,但是&&在這裏意味着什麼呢? – streppel

+3

@strep <瘋狂的笑聲> –

+3

@streppel在這種情況下,它是_forwarding reference_。 [這裏](https://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers)是一個很好的解釋(使用_old_ name,_universal reference_)。 – skypjack

1
template <typename ... A> void executeFunction(int(*func_ptr)(A...), A...) { 
    if (func_ptr(A...) > 0) 
    throw std::runtime_error("Method failed"); 
} 

int func(int A, int B) { 
} 

int main() { 
    int a, b; 
    a = 0; 
    b = 4; 
    executeFunction(func, a, b) 
} 

未測試,但類似這樣的應該工作。

希望它有幫助!

1

以下是一種不需要更改呼叫站點的方法。假設這些C函數都具有相同的返回代碼約定,那麼可以編寫一個將返回代碼轉換爲異常的包裝器。

inline void checked(const char *name, int result) { 
    if (result > 0) 
     throw std::runtime_error(name); 
} 

然後爲每個函數引入一個預處理器定義。

#define functionA(...) checked("functionA", functionA(__VA_ARGS__)) 

這工作,因爲functionA不會在functionA宏的定義中進行擴展。可變宏是C++ 11以來的標準。

+0

或者,[你可以使用一個包裝](http://coliru.stacked-crooked.com/a/1d01560401d1b55f) ,'#define Wrapper(Func,...)checked(#Func,Func(__ VA_ARGS __))'。 –

+1

@JustinTime:True。有一個折衷:這樣,如果你忘記爲函數添加'#define'那麼它將不會被檢查;這樣,如果你忘記在呼叫站點打包,也會發生同樣的事情,但是我認爲可能有更多的呼叫站點一個函數,並且更容易忘記包裝每個調用,所以將整個庫封裝一次是有意義的。 –

+0

這是一個好點,我沒有想到這一點。 –

2

下面是使用C++ 17的新auto模板參數基於模板的解決方案:

template <auto &> struct CallerImpl; 

template <typename ...Args, int (&F)(Args ...)> 
struct CallerImpl<F> 
{ 
    static int CallOrThrow(Args ... args) 
    { 
     if (int n = F(args...); n > 0) 
      throw std::runtime_error("Method failed"); 
     else 
      return n; 
    } 
}; 

template <auto & F, typename ... Brgs> 
int CallOrThrow(Brgs ... brgs) 
{ 
    return CallerImpl<F>::CallOrThrow(brgs...); 
} 

用例:

int foo(double, char) 
{ 
    std::cout << "Foo called\n"; 
    return 8; 
} 

CallOrThrow<foo>(1.5, 'x'); 
+0

[Full demo](http://melpon.org/wandbox/permlink/D6Wz2jsYciPaH3QO) –

+0

不幸的是,我不能使用C++ 17,但它看起來很有前途:) – FloFu

+0

@FloFu:對,如果你不介意讓客戶端功能成爲函數參數而不是模板參數,那麼另一種解決方案絕對是一種可行的方法。但是這種「類型化代表」以前是不可能的(至少不太直接),所以我想我會試一試。 –

2

我知道我會得到downvoted這一點,但我老實說,這是預處理器可以有效使用的一種情況:

#define CHECK(fn) \ 
    { \ 
     if(fn > 0) { \ 
      throw "problem"; \ 
     } \ 
    } 


int f(int x) { 
    return x - 1; 
} 


int main() { 
    CHECK(f(42)); 
} 

很明顯,它很簡單,它很簡單,可以使用__LINE__,__FILE__和其他預定義的宏,這是模板無法做到的。

相關問題