我想创建一个函数,它接受一个弱指针和任何类型的函子(lambda,std::function
,等等)并返回一个新的函子,它只在未删除指针时执行原始函子。与此同时(所以我们假设有一个WeakPointer
类型具有这样的语义)。这应该适用于任何仿函数,而无需通过模板参数或强制转换明确指定仿函数签名。
修改
一些评论者指出,我在我的方法中使用的std::function
可能根本不需要,也不需要lambda(虽然在我原来的问题中我也忘了提到我需要捕获弱指针参数),所以解决一般问题的任何替代解决方案当然也受到高度赞赏,也许我在框外思考不够,并且专注于使用lambda + std::function
。无论如何,这是我到目前为止所做的:
template<typename... ArgumentTypes>
inline std::function<void(ArgumentTypes...)> wrap(WeakPointer pWeakPointer, const std::function<void(ArgumentTypes...)>&& fun)
{
return [=] (ArgumentTypes... args)
{
if(pWeakPointer)
{
fun(args...);
}
};
}
如果我传递std::function
,则无需显式指定参数类型,但如果我传递lambda表达式则失败。我猜这是因为this question中提到的std::function
构造函数歧义。无论如何,我尝试了以下帮助器来捕获任何类型的函数:
template<typename F, typename... ArgumentTypes>
inline function<void(ArgumentTypes...)> wrap(WeakPointer pWeakPointer, const F&& fun)
{
return wrap(pWeakPointer, std::function<void(ArgumentTypes...)>(fun));
}
这现在适用于没有参数但是对其他参数失败的lambda,因为它总是用空集实例化ArgumentTypes...
。
我可以想到两个问题的解决方案,但没有设法实现其中任何一个:
std::function
(或其他Functor助手类型),即带有签名R(T1)
的lambda会产生std::function(R(T1))
,以便{{} 1}}将被正确推断ArgumentTypes...
作为模板参数而是使用其他方式(boost?)从lambda / functor获取参数包,所以我可以这样做:-
ArgumentTypes...
答案 0 :(得分:3)
你不必使用lambda。
#include <iostream>
#include <type_traits>
template <typename F>
struct Wrapper {
F f;
template <typename... T>
auto operator()(T&&... args) -> typename std::result_of<F(T...)>::type {
std::cout << "calling f with " << sizeof...(args) << " arguments.\n";
return f(std::forward<T>(args)...);
}
};
template <typename F>
Wrapper<F> wrap(F&& f) {
return {std::forward<F>(f)};
}
int main() {
auto f = wrap([](int x, int y) { return x + y; });
std::cout << f(2, 3) << std::endl;
return 0;
}
答案 1 :(得分:1)
假设弱指针取代了第一个参数,这就是我用普通lambda(带移动捕获)的方式,如果C ++允许我返回这样的lambda:
template<typename Functor, typename Arg, typename... Args>
auto wrap(Functor&& functor, Arg&& arg)
{
return [functor = std::forward<Functor>(functor)
, arg = std::forward<Arg>(arg)]<typename... Rest>(Rest&&... rest)
{
if(auto e = arg.lock()) {
return functor(*e, std::forward<Rest>(rest)...);
} else {
// Let's handwave this for the time being
}
};
}
如果我们将通用lambda手动“展开”为多态仿函数,则可以将此假设代码转换为实际的C ++ 11代码:
template<typename F, typename Pointer>
struct wrap_type {
F f;
Pointer pointer;
template<typename... Rest>
auto operator()(Rest&&... rest)
-> decltype( f(*pointer.lock(), std::forward<Rest>(rest)...) )
{
if(auto p = lock()) {
return f(*p, std::forward<Rest>(rest)...);
} else {
// Handle
}
}
};
template<typename F, typename Pointer>
wrap_type<typename std::decay<F>::type, typename std::decay<Pointer>::type>
wrap(F&& f, Pointer&& pointer)
{ return { std::forward<F>(f), std::forward<Pointer>(pointer) }; }
有两个简单的选项可用于处理指针已过期的情况:传播异常或返回带外值。在后一种情况下,返回类型将变为例如optional<decltype( f(*pointer.lock(), std::forward<Rest>(rest)...) )>
和// Handle
将成为return {};
。
Example code to see everything in action
[雄心勃勃的练习:改进代码,以便可以使用auto g = wrap(f, w, 4); auto r = g();
。然后,如果情况不是这样,那么进一步改进,以便auto g = wrap(f, w1, 4, w5);
也可以做'做正确的事'。 ]