函数包装器,适用于所有类型的函数,无需强制转换
Function wrapper that works for all kinds of functors without casting
我想创建一个函数,它接受一个弱指针和任何类型的函子(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表达式,则会失败。我想这是因为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...
。
我能想出两种解决问题的方法,但都没能实现:
- 确保为lambda创建了正确的
std::function
(或另一个Functor帮助器类型),即具有签名R(T1)
的lambda会产生std::function(R(T1))
,以便正确推导ArgumentTypes...
- 不要把
ArgumentTypes...
作为模板参数,而是用其他方法(boost?)从lambda/函子中获取参数包,所以我可以这样做:
-
template<typename F>
inline auto wrap(WeakPointer pWeakPointer, const F&& fun) -> std::function<void(arg_pack_from_functor(fun))>
{
return wrap(pWeakPointer, std::function<void(arg_pack_from_functor(fun))(fun));
}
您不必使用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;
}
假设弱指针取代了第一个参数,下面是我如何使用通用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 {};
。
查看所有操作的示例代码。
[雄心勃勃的人练习:改进代码,使其可以使用auto g = wrap(f, w, 4); auto r = g();
。然后,如果还不是这样,则进一步改进,使auto g = wrap(f, w1, 4, w5);
也成为可能,并"做正确的事情"。]
- 如何使用Rcpp将R函数转换为C++函数
- C++函数转换为 C# 函数
- 将 C 函数转换为 C++ 以检查数字是否有效
- C++:从重载函数转换为 std::function
- 将 C 函数转换为C++语言
- C++隐式构造函数转换,后跟类型向上转换
- 将 lambda 函数转换为具有混合 lambda 引入器和参数列表的函子结构
- 通过 Boost Python 将 Python 函数转换为 C++,用作回调
- 如何将 MATLAB 图像处理库内置函数转换为 MATLAB 编码器代码生成不支持的 C++?
- 如何将函数转换为 lambda 函数
- 自定义函数转换错误?
- 将 C# 哈希函数转换为C++
- 将 lambda 函数转换为另一个编译单元中的普通函数会缩短编译时间吗?
- 加快 R 性能或将 R 函数转换为C++函数
- 将成员函数转换为指向成员函数的指针
- 将MATLAB炒作函数转换为C
- Rcpp - 用二进制函数转换数字向量?
- C lambda函数转换误差
- 此语法中的构造函数转换错误
- 将函数转换为find_if lambda