如何在 std::function 上创建一个钩子
How to create a hook on a std::function?
我正在尝试弄清楚如何用"之前"和"之后"钩子装饰std::function
。
我在找出正确的语法时遇到了一些麻烦。这是我到目前为止所拥有的:
// create a "before" hook
template<typename Functor, typename Hook>
Functor hook_before(const Functor & original, Hook hook)
{
// not legal, but illustrates what I want to achieve
template<typename Args ...args>
return [=](Args ...args)
{
hook();
original(args...);
};
}
我的示例应用程序在 Ideone 上。
谁能帮我弄清楚?
你可以这样做:
#include <functional>
#include <iostream>
template <class Hook, class ReturnType, class... ArgType>
std::function<ReturnType(ArgType...)> hook_before(
const std::function<ReturnType(ArgType...)>& original,
Hook hook)
{
return [=](ArgType... args){
hook();
return original(std::move(args)...);
};
}
int main()
{
std::function<int(int, int)> sum = [](int a, int b) { return a + b; };
std::cout << sum(3, 4) << std::endl;
auto myhook = []() { std::cout << "Calculating sum" << std::endl; };
auto hooked_sum = hook_before(sum, myhook);
std::cout << hooked_sum(3, 4) << std::endl;
}
hook_before
函数接受两个函子,并返回另一个接受与第一个函子相同的参数(ArgType 参数包),但首先调用hook
函子。
这里是(未经测试):
template <typename HOOK, typename RET, typename... ARGS>
struct BeforeHook {
std::function<RET(ARGS...)> functor;
HOOK hook;
BeforeHook(blah) : blah {};
RET operator()(ARGS&&... args) const {
hook();
return functor(args...);
}
};
template <typename HOOK, typename RET, typename... ARGS>
BeforeHook<HOOK, RET, ARGS...> hook_before(const std::function<RET(ARGS...)> &original, HOOK hook) {
return BeforeHook<HOOK, RET, ARGS...>(original, hook);
}
用法:
auto hooked = hook_before(original_functor, hook_functor);
hooked(args_for_original_functor); // calls hook_functor, then original_functor
或者类似的东西。original_functor需要可转换为std::function
,但几乎所有可调用的东西都是可调用的。这两个函子都需要成本可调用,但如果您愿意,您可以从operator()
中删除const
。
如果您想尝试返回 lambda 而不是 BeforeHook
的实例,请对模板参数 RET
和 ...ARGS
使用相同的技巧,并找出是否可以在 lambda 中使用模板参数包:
template <typename HOOK, typename RET, typename... ARGS>
std::function<RET(ARGS...)> hook_before(const std::function<RET(ARGS...)> &original, HOOK hook) {
return [=](ARGS&&... args) -> RET {
hook();
return original(args...);
};
}
无论哪种方式,我认为关键技巧是在模板参数推导中使用std::function
将返回类型与参数分开。
尝试以下操作。
template<typename Functor, typename Hook>
struct BeforeHooked
{
Functor f;
Hook hook;
template<class... Args>
typename std::result_of<F(Args&&...)>::type
operator()(Args&&... args)
{
hook();
return f(std::forward<Args&&>(args)...);
}
};
template<typename Functor, typename Hook>
Functor hook_before(Functor f, Hook hook)
{
return BeforeHooked{f, hook};
}
代码未经测试,但假设你有一个可以编译它的编译器,我认为它应该做你想要的。与其他答案不同,它可以接受任何函子,而不仅仅是std::function
,如果你给它一个多态函子,它仍然是多态的。
相关文章:
- 如何创建一个CMake变量,除非显式重写,否则使用默认值
- 创建一个函数以在输入为负数或零时输出字符串.第一次执行用户定义的函数
- 试图在visual studio上用C++创建一个桌面应用程序
- 如何创建一个空的全局类并在启动时实例化它
- 有没有一种方法可以创建一个带有哈希表的数据库,该哈希表具有恒定时间查找功能
- 如何创建一个QTableWidgetItem,用长文本右对齐,左边有省略号
- 我正在尝试使用 c++ 创建一个货币转换程序,我不知道如何继续
- visual是否可以在c++中创建一个接收无限数量相同类型(或至少相当数量)参数的函数
- C++-我可以创建另一个类的成员并在构造函数中使用它吗
- 试图创建一个多线程程序来查找0-100000000之间的总素数
- 如何创建一个函数来计算并返回平均值、最大值和最小值
- 如何使用CLion在Mac上创建一个新的.txt文件
- 如何在没有数据拷贝的情况下从指针创建一个Eigen VectorXd对象
- 在c++中为double类型的数组创建一个unique_ptr
- 如何创建函数管道,以便函数一个接一个地运行?
- 如何从这些语句中的每一个创建不同的函数?
- 给定一个创建的带有货物的链表,我需要使用函数检查实际序列或"train"是否有效
- 一个创建彩票游戏的程序,该彩票游戏可以有效地创建 10 套而没有任何重复?
- 如何实现一个创建新对象并返回对它的引用的C++方法
- 如何成功创建一个创建对象并返回指向该对象的指针的函数