c++ - 返回 std::function 的类 std::bind 函数

标签 c++ templates c++11 bind

我需要一个 bind行为类似于 std::bind 的函数, 但返回 std::function 的适当特化.

我认为 std::function可以使用函数参数中的占位符编号提取模板参数。这看起来并不那么微不足道。是否已经有可用的实现?


为什么我需要这个

我想实现一个 waterfall语义类似于 this JavaScript one 的函数.

这是我想象中的 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会将每个函数绑定(bind)到前一个函数(当然是从最后一个函数开始),并返回一个函数。

基本上瀑布应该是这样的:

// 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)...) );
}

虽然存在三个 Unresolved 问题:

  1. 找出 waterfall 的返回类型当使用多个参数调用时。不能是 decltype( std::bind(first, waterfall(...)) ) (因为 C++ 不允许递归调用模板函数来推断其类型)。如果我知道函数的类型(即 Arg ),那么在没有第一个参数的情况下,这就是我正在寻找的返回类型。
  2. 我想我需要知道 first 的参数个数为了正确std::bind
  3. std::bind的返回类型不符合我的要求:嵌套 std::bind调用将所有绑定(bind)函数合并在一起,而不是组合它们。

我可以通过写 std::bind 绕过第三点将绑定(bind)函数包装到 T 类型的对象中的包装器这样 std::is_bind_expression<T>::value == false .

对于前两点,我需要找出 waterfall 的返回类型和参数类型参数。如果函数是 std::function,这将是微不足道的秒。如果它们是 lambda、经典函数或具有单个 operator() 的仿函数,它也会很简单:我只需要使用类似 this function_traits 的东西.但是我真的想传递使用 std::bind 绑定(bind)的函数至 waterfall , 而无需手动将它们转换为 std::function s,因为这使我的代码方式更短并且方式更清晰大 waterfall

有什么想法、想法或建议吗?

最佳答案

此处的设计是在辅助类 details::waterfall 中完成大部分工作,并在 waterfall_call 中完成 2 函数瀑布式组合。

#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...:

    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 args,递归,然后执行 2 arg 解决方案:

    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 本身只是委托(delegate)给 details::waterfall:

template<class...Fs>
auto waterfall(Fs&&... fs )
-> typename std::result_of<details::waterfall(Fs...)>::type{
  return details::waterfall{}( std::forward<Fs>(fs)... );
}

live example

绕过递归模板返回类型推导限制的另一种方法(除了上面的 struct 技巧之外)是从函数的命名空间中按模板类型获取参数,并将其传递给递归电话。这将启用 ADL 查找,即使在推导您自己的返回类型时,它也可以递归地找到您自己的函数。

关于c++ - 返回 std::function 的类 std::bind 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29174498/

相关文章:

c++ - 编译器说了多个定义,但我找不到任何定义

c++ - 服务器线程与人机界面 (MMI) 之间的通信

c++ - 如何使用枚举定义容器模板

c++ - 继承自 shared_ptr<void>

c++ - 如何使用类模板特化创建别名模板的特化?

c++ - Arduino HC-SR04 传感器,平均数据

javascript - 达到 10 次摘要迭代,正在中止(作用域函数问题)

c++ - 我应该如何递归调用模板函数?

c++ - 当 decltype 应用于它们时,哪些表达式会产生引用类型?

c++ - decltype 声明函数返回类型的参数(无自动)