std::bind 类函数返回 std::function
std::bind-like function returning a std::function
我需要一个行为类似于 std::bind
的 bind
函数,但 return 是 std::function
的适当专业化。
我认为可以使用函数参数中的占位符编号提取 std::function
模板参数。这看起来并不那么微不足道。是否已经有可用的实现?
为什么我需要这个
我想实现一个语义类似于 this JavaScript one 的 waterfall
函数。
下面是我想象的 C++ 中的样子:
std::function<void(const std::string &)> f = waterfall(
[]( const std::function<void(int)> &cb, const std::string & ) {
...;
cb( 1 );
},
[]( const std::function<void(double, double)> &cb, int ) {
...;
cb(0.5, 10);
},
[]( double, double ) {
}
);
换句话说,waterfall
会接受一堆函数,每个函数(但最后一个)都接受一个函数作为第一个参数。 waterfall
会将每个函数绑定到前一个函数(当然是从最后一个函数开始),return 一个函数。
基本上瀑布应该是这样的:
// recursion termination: `waterfall` called with a single functions
template< typename Arg >
auto waterfall( const Arg& first ) -> decltype( first ) {
return first;
}
// recursion: `waterfall` called with mulitple functions
template< typename Arg, typename... Args >
... waterfall( const Arg& first, Args... args ) {
return std::bind( first, waterfall(std::forward<Args>(args)...) );
}
虽然存在三个未解决的问题:
- 在使用多个参数调用时找出
waterfall
的 return 类型。它不能是 decltype( std::bind(first, waterfall(...)) )
(因为 C++ 不允许递归调用模板函数来推断其类型)。如果我知道函数的类型(即 Arg
),那么在没有第一个参数的情况下,将是我正在寻找的 return 类型。
- 我想我需要知道
first
的参数数量才能正确 std::bind
它。
std::bind
的 return 类型不符合我的要求:嵌套 std::bind
调用 合并 所有绑定函数, 而不是组合它们。
我可以通过编写一个 std::bind
包装器来绕过第三点,该包装器将绑定函数包装到 T
类型的对象中,这样 std::is_bind_expression<T>::value == false
.
对于前两点,我需要找出 return 类型和 waterfall
参数的参数类型。如果函数是 std::function
s,这将是微不足道的。如果它们是 lambda、经典函数或具有单个 operator()
的仿函数,它也会很简单:我只需要使用类似 this function_traits
的东西。然而,我 真的 喜欢将使用 std::bind
绑定的函数传递给 waterfall
,而不必手动将它们转换为 std::function
s,因为这使得我的代码 way 更短 way 更清晰 waterfall
s.
有什么想法、想法或建议吗?
此处的设计是在助手 class 中完成大部分工作 details::waterfall
2 函数瀑布式组合在 waterfall_call
中完成。
#include <iostream>
#include <utility>
#include <functional>
#include <string.h>
namespace details {
如果我在结构定义之外衰减,这会稍微更有效率,因为在某些情况下它会减少唯一类型。我不在乎:
template<class F0, class F1>
struct waterfall_call {
typename std::decay<F0>::type f0;
typename std::decay<F1>::type f1;
调用 f0 传递给它 f1 和 args...:[=25=]
template<class...Args>
auto operator()(Args&&... args)const
-> typename std::result_of<F0 const&(F1 const&,Args...)>::type
{
return f0( f1, std::forward<Args>(args)... );
}
};
算法中心:
struct waterfall {
对于 2 个参数,只需使用 waterfall_call
:
template<class F0, class F1>
waterfall_call<F0, F1> operator()( F0&& f0, F1&& f1 )const
{
return { std::forward<F0>(f0), std::forward<F1>(f1) };
}
对于 >2 个参数,递归,然后执行一个 2 个参数的解决方案:
template<class F0, class...Fs,
class I=typename std::result_of<waterfall const&(Fs...)>::type
>
auto operator()( F0&& f0, Fs&&... fs )const
-> typename std::result_of< waterfall( F0, I ) >::type
{
auto child = (*this)( std::forward<Fs>(fs)... );
return (*this)( std::forward<F0>(f0), std::move(child) );
}
对于 1 个 arg,只需转发到输入 arg 的衰减版本:
template<class F0>
auto operator()(F0&&f0)const
->typename std::decay<F0>::type
{
return std::forward<F0>(f0);
}
};
}
而waterfall
本身只是委托给details::waterfall
:
template<class...Fs>
auto waterfall(Fs&&... fs )
-> typename std::result_of<details::waterfall(Fs...)>::type{
return details::waterfall{}( std::forward<Fs>(fs)... );
}
绕过递归模板return类型推导限制的另一种方法(除了上面的struct
技巧外)是从函数的命名空间中按模板类型获取参数,并将其传递到你的递归调用。这将启用 ADL 查找,即使在推导您自己的 return 类型时,它也可以递归地找到您自己的函数。
我需要一个行为类似于 std::bind
的 bind
函数,但 return 是 std::function
的适当专业化。
我认为可以使用函数参数中的占位符编号提取 std::function
模板参数。这看起来并不那么微不足道。是否已经有可用的实现?
为什么我需要这个
我想实现一个语义类似于 this JavaScript one 的 waterfall
函数。
下面是我想象的 C++ 中的样子:
std::function<void(const std::string &)> f = waterfall(
[]( const std::function<void(int)> &cb, const std::string & ) {
...;
cb( 1 );
},
[]( const std::function<void(double, double)> &cb, int ) {
...;
cb(0.5, 10);
},
[]( double, double ) {
}
);
换句话说,waterfall
会接受一堆函数,每个函数(但最后一个)都接受一个函数作为第一个参数。 waterfall
会将每个函数绑定到前一个函数(当然是从最后一个函数开始),return 一个函数。
基本上瀑布应该是这样的:
// recursion termination: `waterfall` called with a single functions
template< typename Arg >
auto waterfall( const Arg& first ) -> decltype( first ) {
return first;
}
// recursion: `waterfall` called with mulitple functions
template< typename Arg, typename... Args >
... waterfall( const Arg& first, Args... args ) {
return std::bind( first, waterfall(std::forward<Args>(args)...) );
}
虽然存在三个未解决的问题:
- 在使用多个参数调用时找出
waterfall
的 return 类型。它不能是decltype( std::bind(first, waterfall(...)) )
(因为 C++ 不允许递归调用模板函数来推断其类型)。如果我知道函数的类型(即Arg
),那么在没有第一个参数的情况下,将是我正在寻找的 return 类型。 - 我想我需要知道
first
的参数数量才能正确std::bind
它。 std::bind
的 return 类型不符合我的要求:嵌套std::bind
调用 合并 所有绑定函数, 而不是组合它们。
我可以通过编写一个 std::bind
包装器来绕过第三点,该包装器将绑定函数包装到 T
类型的对象中,这样 std::is_bind_expression<T>::value == false
.
对于前两点,我需要找出 return 类型和 waterfall
参数的参数类型。如果函数是 std::function
s,这将是微不足道的。如果它们是 lambda、经典函数或具有单个 operator()
的仿函数,它也会很简单:我只需要使用类似 this function_traits
的东西。然而,我 真的 喜欢将使用 std::bind
绑定的函数传递给 waterfall
,而不必手动将它们转换为 std::function
s,因为这使得我的代码 way 更短 way 更清晰 waterfall
s.
有什么想法、想法或建议吗?
此处的设计是在助手 class 中完成大部分工作 details::waterfall
2 函数瀑布式组合在 waterfall_call
中完成。
#include <iostream>
#include <utility>
#include <functional>
#include <string.h>
namespace details {
如果我在结构定义之外衰减,这会稍微更有效率,因为在某些情况下它会减少唯一类型。我不在乎:
template<class F0, class F1>
struct waterfall_call {
typename std::decay<F0>::type f0;
typename std::decay<F1>::type f1;
调用 f0 传递给它 f1 和 args...:[=25=]
template<class...Args>
auto operator()(Args&&... args)const
-> typename std::result_of<F0 const&(F1 const&,Args...)>::type
{
return f0( f1, std::forward<Args>(args)... );
}
};
算法中心:
struct waterfall {
对于 2 个参数,只需使用 waterfall_call
:
template<class F0, class F1>
waterfall_call<F0, F1> operator()( F0&& f0, F1&& f1 )const
{
return { std::forward<F0>(f0), std::forward<F1>(f1) };
}
对于 >2 个参数,递归,然后执行一个 2 个参数的解决方案:
template<class F0, class...Fs,
class I=typename std::result_of<waterfall const&(Fs...)>::type
>
auto operator()( F0&& f0, Fs&&... fs )const
-> typename std::result_of< waterfall( F0, I ) >::type
{
auto child = (*this)( std::forward<Fs>(fs)... );
return (*this)( std::forward<F0>(f0), std::move(child) );
}
对于 1 个 arg,只需转发到输入 arg 的衰减版本:
template<class F0>
auto operator()(F0&&f0)const
->typename std::decay<F0>::type
{
return std::forward<F0>(f0);
}
};
}
而waterfall
本身只是委托给details::waterfall
:
template<class...Fs>
auto waterfall(Fs&&... fs )
-> typename std::result_of<details::waterfall(Fs...)>::type{
return details::waterfall{}( std::forward<Fs>(fs)... );
}
绕过递归模板return类型推导限制的另一种方法(除了上面的struct
技巧外)是从函数的命名空间中按模板类型获取参数,并将其传递到你的递归调用。这将启用 ADL 查找,即使在推导您自己的 return 类型时,它也可以递归地找到您自己的函数。