我正在包装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;
}
受访者指出,变量模板必须足够通用。这是一个开始,但我迷失了,并对此事的任何帮助表示感谢。
答案 0 :(得分:1)
我认为你将能够使用这种语法:
wrap(&SomeAPIFunction, arg1, arg2);
关键是让编译器使用类型推导来确定模板类型参数,因为它们很快就会变得非常混乱。
代码应该类似于:
template<typename TRet, typename... TArgs>
TRet wrap( TRet(WINAPI *api)(TArgs...), TArgs... args )
{
return api(args...);
}
当然,您需要使用宏来隐藏函数地址运算符,使用字符串化来存储函数名称,并存储文件名和行号,将所有这些传递给实际的可变参数函数。你需要variadic宏。事实上,你能用变量宏和没有模板来做所有这些吗?