包装任何API函数

时间:2012-02-28 21:00:55

标签: c++ function templates wrapper variadic

我正在包装Windows API,我希望使错误检查易于使用,并且很有帮助。目前,我有一个全局错误对象,函数set来处理新错误。 set函数有四个参数:bool Error::set (const int code, const char * file, const char * const function, const int line);该函数使用file,function和line参数在格式正确的消息中显示它们。

为了简化错误设置,有一个宏#define setError() error.set (GetLastError(), __FILE__, __FUNCTION__, __LINE__);这样我就可以随时使用setError()来响应API函数设置的错误我称之为API函数。

不幸的是,这导致代码看起来像这样:

SomeAPIFunction();
setError();
AnotherAPIFunction();
setError();

构造函数也存在问题:

MyClass:MyClass()
    : a (SomeAPIFunction), b (AnotherAPIFunction)
{
    setError(); //what if both functions set an error?
}

正如您所看到的,通过使用成员初始化程序语法,我实际上限制了自己。

解决这个问题的一种方法是包装每个API函数:

int someAPIFunction()
{
    int ret = SomeAPIFunction();
    setError();
    return ret;
}

错误消息的function部分会告诉我哪个函数产生了错误。当然,这必须是解决这个问题的最糟糕方式。

似乎解决方案是使用可变参数模板。问题是,我不知道我应该做些什么让他们为此工作。我想最终的代码看起来像下列之一:

wrap<int, SomeAPIFunction (5)>();
wrap<int, SomeAPIFunction, 5>();
wrap<int, SomeAPIFunction> (5);

我已经阅读了开始可变参数模板的内容,但是他们都让我不知道如何设置这样的东西。有人能指出我正确的方向吗?

我在a similar question上找到了以下内容:

#include <iostream>

template<void f(void)>
struct Wrap {
   void operator()() const {
      std::cout << "Pre call hook" << std::endl;
      f();
   }
};

namespace {
   void test_func() {
      std::cout << "Real function" << std::endl;
   }
}

const Wrap<&test_func> wrapped_test_func = {};

int main() {
   wrapped_test_func();
   return 0;
}

受访者指出,变量模板必须足够通用。这是一个开始,但我迷失了,并对此事的任何帮助表示感谢。

1 个答案:

答案 0 :(得分:1)

我认为你将能够使用这种语法:

wrap(&SomeAPIFunction, arg1, arg2);

关键是让编译器使用类型推导来确定模板类型参数,因为它们很快就会变得非常混乱。

代码应该类似于:

template<typename TRet, typename... TArgs>
TRet wrap( TRet(WINAPI *api)(TArgs...), TArgs... args )
{
    return api(args...);
}

当然,您需要使用宏来隐藏函数地址运算符,使用字符串化来存储函数名称,并存储文件名和行号,将所有这些传递给实际的可变参数函数。你需要variadic宏。事实上,你能用变量宏和没有模板来做所有这些吗?