我正在编写一个使用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的解决方案不在桌面上,因为调用代码无法使用它们。
答案 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>;
答案 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 *>;