C++14 lambda 实现 bind_front
用lambda C++14实现bind_front,这段代码还有没有优化空间? - 知乎 (zhihu.com)
template<typename Func, typename Tuple, std::size_t ... I, typename ...Args, std::enable_if_t<!std::is_member_function_pointer<Func>::value, int> = 0>
constexpr
decltype(auto) bind_front_impl(Func&& f, Tuple&& fargs, std::index_sequence<I...>, Args && ... args)
{
return (std::forward<Func>(f))(std::get<I>(fargs)..., std::forward<decltype(args)>(args)...);
}
template<typename Func, typename Tuple, std::size_t ... I, typename ...Args, std::enable_if_t<std::is_member_function_pointer<Func>::value, int> = 0>
constexpr
decltype(auto) bind_front_impl(Func&& f, Tuple&& fargs, std::index_sequence<I...>, Args && ... args)
{
return std::mem_fn(std::forward<Func>(f))(std::get<I>(fargs)..., std::forward<decltype(args)>(args)...);
}
template <typename Func, typename ...Args>
constexpr
decltype(auto) bind_front(Func&& f, Args && ... args)
{
// std::forward_as_tuple 会将 args 的引用保存在 tuple中,不安全,因此用std::make_tuple将参数拷贝一份
// 如果要保持传入参数的引用,参考 std::bind,使用 std::ref 包装
// 不加 mutable 会调用 operator() const,加了mutable之后,调用 operator(),但lambda无法赋值给const变量
return[f, fargs = std::make_tuple(std::forward<Args>(args)...)](auto &&...args) -> decltype(auto)
{
// 此时 fargs 相当于闭包类型的成员变量,调用 f 时直接传入,不能转发进f(如果转发进f,则lambda调用一次之后, fargs中参数的生命周期结束)
// 不用 tuple_cat 将 fargs、args 打包到一起,是因为 fargs 中可能存在不允许copy的对象
// 如果用tuple_cat打包到一起,意味着 fargs 要 forward 到新的tuple中,那么 fargs 中的参数生命周期结束
// const_cast<Func&&>(f) 为了正确处理仿函数,与入参类型保持一致
// 直接写 args... 会导致无法转发不能拷贝的对象,无法正确转发参数
return bind_front_impl(const_cast<Func&&>(f), const_cast<decltype(fargs)&>(fargs), std::index_sequence_for<Args...>(), std::forward<decltype(args)>(args)...);
};
}
已知问题
默认参数传入不可copy参数,形参必须是引用
// int test1(std::unique_ptr<int> ptr1) // 编译失败 int test1(const std::unique_ptr<int> &ptr1) { printf("&ptr1 = %p\n", ptr1.get()); return *ptr1; } auto f = bind_front(test1, std::make_unique<int>(1)); // 在C++20中,出现这种情况则不允许赋值给f,只能立即调用