未知的功能模板参数

时间:2014-04-22 20:43:25

标签: c++ templates c++11 function-templates

我正在编写一个基本上挂钩Windows API并记录参数和结果的应用程序分析库。我试图想出一种使用C ++模板生成这些钩子的方法,这种模板只需要很少的工作就可以添加新的钩子。基本上,我的每个钩子都如下所示:

BOOL HookCloseHandle(HANDLE h)
{
    BOOL result = RealCloseHandle(h);
    if(g_profiling) record(result, h);
    return result;
}

我想通过模板来概括,以便可以通过decltype为任意Windows API函数生成这些函数,例如: decltype(CreateFileW)。这甚至可能吗?我一直在看Boost中的function_traits,似乎我能够想出一些接近的东西:

decltype(&CloseHandle) RealCloseHandle = &::CloseHandle;

template <typename R, typename P1, R(*F)(P1)>
R perform_1(P1 value)
{
    R result = F(value);
    if (profiling) record(result, value);
    return result;
}

template <typename T>
T* call(const T& original)
{
    typedef boost::function_traits<T> traits;
    switch (traits::arity)
    {
        case 1:
            return &perform_1<traits::result_type, traits::arg1_type, RealCloseHandle>;
        // ...
    }
    return nullptr;
};

// setup code
Hook(RealCloseHandle, call<decltype(CloseHandle)>());

挂钩库提供Hook取代&#34;真实&#34;功能与我的钩子版本。

唯一的问题是,我不确定如何删除当前CloseHandle函数中的call模板参数。有什么想法吗?

1 个答案:

答案 0 :(得分:0)

嗯,基础知识看起来像这样:

//declare the Wrap type
template<class signature, signature func> struct Wrap;

//template parameters are return type, parameter list, then the actual function
template<class R, class...Ps, R(&func)(Ps...)> 
struct Wrap<R(Ps...), func>
{        
    static R MSVCSTDCALL call(Ps...Vs) GCCSTDCALL
    {
        auto result = func(Vs...);
        if (g_profiling) record_w_ret(Wrap(), result, Vs...);
        return result;
    }
};

//pass the call function of the Wrap object
Hook(CloseHandle, Wrap<void(HANDLE),CloseHandle>::call);

但是,这不会处理void返回,因此我们需要专门化:

//Wrappers without returns
template<class...Ps, void(&func)(Ps...)> 
struct Wrap<void(Ps...), func>
{        
    static void MSVCSTDCALL call(Ps...Vs) GCCSTDCALL
    {
        func(Vs...);
        if (g_profiling) record_no_ret(Wrap(), Vs...);
    }
};

并修复丑陋的使用语法:

//easymode wrapper
#define WRAP(X) Wrap<decltype(X),X>::call

Hook(CloseHandle, WRAP(CloseHandle));

但是,有人指出,使用函数指针作为非类型模板参数是非法的,G ++不会接受它。我会继续努力的。 Clang和MSVC接受他们的罚款。