我想弄清楚如何用“之前”和“之后”钩子来装饰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。
任何人都可以帮我搞清楚吗?
答案 0 :(得分:3)
这里(未经测试):
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
,但几乎所有可调用的都是。两个仿函数都需要成本可调,但如果您愿意,可以从const
删除operator()
。
如果您想尝试返回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
来将返回类型与参数分开。
答案 1 :(得分:3)
你可以这样做:
#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
。
答案 2 :(得分:2)
请尝试以下操作。
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
,如果你给它一个多态函子,它仍然是多态的。