使用C ++模板包装第三方C代码

时间:2014-04-22 14:41:58

标签: c++ templates c++11 hook

我正在编写一个使用Function Hooking来检查从第三方代码发送到第三方库的参数的库。调用者和被调用者都是用C语言编写的,并且通过为加载器提供一组函数指针对来完成挂钩。

最初,我在C中写了这个,并为每个函数钩子复制了一个 lot 代码。在编写了一些钩子之后,我查看了C ++模板以减轻负载。

以下示例使用固定数量的模板参数并演示了这个想法:

#include <cstdio>
#include <iostream>

typedef int (*PrintCallback)(const char *);

int PrintSingle(const char *input)
{
    return printf("%s", input);
}

template<typename Result,
         typename Arg,
         Result(*callback)(Arg)>
Result WrapFunc(Arg arg)
{
    std::cout << "Logging logic goes here..." << std::endl;
    return callback(std::forward<Arg>(arg));
}

int main(int argc, char *argv[])
{
    PrintCallback pc = WrapFunc<int, const char *, PrintSingle>;
    pc("Hello, World!\n");
    return 0;
}

输出:

Logging logic goes here...
Hello, World!

当我尝试使用C ++ 11的Variadic模板将此解决方案概括为可变数量的模板参数时,我遇到了麻烦:

template<typename Result,
         typename... Args,
         Result(*callback)(Args...)>
Result WrapFunc(Args... args)
{
    std::cout << "Logging logic goes here..." << std::endl;
    return callback(std::forward<Args>(args)...);
}

当我尝试实例化这个模板时,不清楚最后一个模板参数是否是&#34;回调&#34;价值或者#34; Args&#34;的一部分。我的编译器返回此错误消息:

variadic.cpp:22:21: error: address of overloaded function 'WrapFunc' does not
      match required type 'int (const char *)'
        PrintCallback pc = WrapFunc<int,const char *, PrintSingle>;
                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
variadic.cpp:14:8: note: candidate template ignored: invalid
      explicitly-specified argument for template parameter 'Args'
Result WrapFunc(Args... args)

然而,我不能交换&#34; Args&#34;的顺序。和#34;回调&#34;在模板中,因为回调的类型取决于Args的定义。

有没有办法正确地做到这一点,以便我可以提供一个C函数指针到加载器的表?依赖于在运行时返回std :: functions的解决方案不在桌面上,因为调用代码无法使用它们。

2 个答案:

答案 0 :(得分:1)

这里的问题是你不能在一个可变参数包之后放置更多的参数:他们试图贪吃地吃掉所有东西。您通常可以通过引入一个间接层,模板样式来解决这个问题:

template <typename Result, typename...Args>
struct Wrap {
    template <Result(*callback)(Args...)>
    static Result Func(Args...args) {
        std::cout << "Logging logic goes here...\n";
        return callback(std::forward<Args>(args)...);
    }
};

需要稍微修改您的使用语法:

PrintCallback pc = Wrap<int, const char *>::Func<PrintSingle>;

See it live at Coliru.

答案 1 :(得分:1)

您可以使用:(https://ideone.com/OaNtMz

template<typename F, F f, typename... Args>
auto WrapFunc(Args... args) -> decltype(f(std::forward<Args>(args)...))
{
    std::cout << "Logging logic goes here..." << std::endl;
    return f(std::forward<Args>(args)...);
}

然后:

PrintCallback pc = &WrapFunc<decltype(&PrintSingle), &PrintSingle, const char *>;