2017-01-27 159 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__和其他预定义的宏,这是模板无法做到的。

相关问题