函数的包装避免重复
wrap of functions avoid duplicating
我有第三方C库。我想在c++中使用它每个函数返回错误代码。当我必须使用它时,我必须编写这样的代码:
int err;
err=libFun1(....);
check(err);
err=libFun2(....);
check(err);
我想包装这个函数,避免代码重复检查。这个库的每个函数都有不同数量的参数。什么是好的设计呢?
模板化函数如何:
template <typename T>
int CallWrapper(T func)
{
int error = func();
check(error);
return error;
}
然后用CallWrapper(libFun1);
调用
/edit 4: c++ 11-Way使用可变模板,灵感来自Gill Bates的解决方案:
template <typename T, class ...A> int CallWrapper(T func, A... args) {
int error = func(args...);
check(error);
return error;
}
CallWrapper(libFun1);
CallWrapper(libFun2, 4711);
CallWrapper(libFun3, 42, 23);
/edit 5:旧的解,从第一个解开始:
#define LIBFUN1() do {
int err = libFun1();
check(err);
} while (0)
#define LIBFUN2() do {
int err = libFun2();
check(err);
} while (0)
LIBFUN1();
LIBFUN2();
把#define
放到某个头文件中。请注意while ()
后面的MISSING分号。这样,您就可以在任何允许像if (...) LIBFUN1(); else LIBFUN2();
LIBFUN1()
等等。/edit 3:不使用#define
s,静态内联函数也可以完成这项工作:
static inline int checked_libFun1() {
int err = libFun1();
check(err);
return err;
}
static inline int checked_libFun2() {
int err = libFun2();
check(err);
return err;
}
checked_libFun1();
checked_libFun2();
/edit 2: @Myst建议使用可变宏,其中包含要调用的函数的名称。可以像这样:
#define call_void(name) do {
int err = name();
check(err);
} while (0)
#define call_args(name, ...) do {
int err = name(__VA_ARGS__);
check(err);
} while (0)
call_void(libFun1);
call_args(libFun2, 42);
这两个宏是必需的,因为您必须区分不接受任何参数的函数和接受大于一个参数的任意数量的函数。这里,libFun2(42)
将被命名为
您可以使用异常并捕获它们。
一种方法是使用宏,如:#include <exception>
#define THROW_ON_ERROR(libFunc) do{
int err = libFunc();
if(check(err))
throw std::exception();
}while(0);
,你的代码看起来像这样:
try
{
THROW_ON_ERROR(libFun1);
THROW_ON_ERROR(libFun2);
}catch(const std::exception& e)
{
//handle...
}
这个方法不是很现代,但可以完成任务。它只是传递了将错误状态代码惯例(C中常见的方式)转换为异常处理的点,这在c++中是一种很好的方式(不确定是否常见)。您还可以使用自己的异常来传递一些数据。您可以通过调用如下函数来做同样的事情:
#include <functional>
class LibFuncException : public std::exception
{
public:
explicit LibFuncException(int err) : m_err(err) {}
int GetError() const { return m_err; }
private:
int m_err;
};
void ThrowOnError(std::function<int()> libFunc)
{
int err = libFunc();
if(check(err)
throw LibFuncException(err);
}
和你的代码可以:
try{
ThrowOnError(libFunc1);
ThrowOnError(libFunc2);
} catch(const LibFuncException& e)
{
std::cout << "Error: << e.GetError() << std::endl;
}
编辑:如果您的库函数有时接收参数,您可以使用lambda调用ThrowOnError
,如下所示:
int x = 10;
const char* str = "Hello World";
ThrowOnError([x, str]() { return libFuncWithArgs(x, str); });
或者如果你想更极端,你可以有一个可变的模板,就像有人建议的那样
从给定的代码中,您可以简单地编写
check(libFun1(/*...*/));
check(libFun2(/*...*/));
可能,您可能希望包装每个方法,以便只有一个来自用户端的调用:
void chekedLibFun1(/*...*/) { check(libFun1(/*...*/)); }
void chekedLibFun2(/*...*/) { check(libFun2(/*...*/)); }
,因此前面的代码变成:
checkedLibFun1(/*...*/);
checkedLibFun2(/*...*/);
我有几种方法可以做到这一点:
- 模板函数(@GillBates有你覆盖)。
- 一个内联函数(可能带有可变参数)。
- 简单的宏(@usr和@ZivS你已经覆盖)。 一个可变宏
既然你是用c++写的,我可能会用模板函数…
该选项唯一的缺点是函数参数处理(假设库函数接受参数)可能会令人头痛。我认为可变宏的C方法会工作得更好,还提供编译时展开(相对于运行时展开)。
。(这只是一个例子,我甚至没有测试代码)
int checkerr(int err) {
if(!err)
return 0;
// ... handle errors, exit if need be.
}
#define CALL_CLIB(fn_name, ...) checkerr((fn_name)(__VA_ARGS__))
你可以这样使用:
// will print "this is only 1 example"
CALL_CLIB(printf, "this is only %d, %s", 1, "example");
如果你愿意,你也可以让它更复杂,添加try
, catch
或任何你想要的混合
- 我的包装函数缺少变量?
- 为什么这个"ctypes"包装函数的返回值是"c_long(0)"而不是&quo
- 如何将包装类的对象用作包装函数中的参数
- 包装C++函数以使用 SWIG 获取 Lua 字符串表
- 带有默认参数的宏包装函数调用
- 如何使用模板函数参数编写包装函数,该功能可以采用超载的成员函数
- 创建一个__cdecl以在 C++ 上__thiscall包装函数
- 在C++中实现和包装函数组合以进行惰性计算
- c++11:如何编写一个包装函数来生成"std::function"对象
- 为什么 Dart 中的原生包装函数与非常轻量级的函数相比"DEFINE NATIVE ENTRY"如此重量级?
- 在 C++ 中使用 map,并提供包装函数以在 C 语言中使用它
- 包装函数只有在链接为静态时才从链接库调用
- 尝试包装函数返回值时出现"<类名>不提供调用运算符"错误
- 交叉编译器/平台裸包装函数,无条件跳转到函数指针
- realloc C 函数的可能包装函数有什么错误?
- 包装 C++ 函数以在 C# 中使用
- 采用"pass by reference"值的递归函数的包装函数
- C++包装函数(宏)来访问 COM 对象属性
- 包装函数指针和函数对象在泛型代码中是如何工作的
- 在c++类中直接包装函数