如何将std :: bind与标准库一起使用并保存返回类型?

时间:2017-08-29 20:33:11

标签: c++ c++11 stl bind

我正在研究一个通过将它们绑定在队列中来调度函数的类:

std::queue <void()> q;

template<typename R,typename... ArgsT>
        void
        schedule(R& fn, ArgsT&... args)
        {
            q.push(std::bind(fn, std::forward<ArgsT>(args)...) );
        };

template<typename R,typename... ArgsT>
        void
        schedule(R&& fn, ArgsT&&... args)
        {
            q.push(std::bind(fn, std::forward<ArgsT>(args)...) );
        };

如您所见,我在queue void()中创建了类型以使其保存任何类型的函数对象,但现在我执行它时无法获得返回。我该怎么做才能解决这个问题?

注意:我不想使用像boost这样的外部库,我不知道用户会传递什么样的函数。

2 个答案:

答案 0 :(得分:4)

  

注意:我不想使用像boost这样的外部库而我不这样做   知道用户将通过它的功能是什么。

在这种情况下我通常做的是在队列中使用基类(来自Command模式),然后有两个实现,一个包装绑定,另一个(也包装绑定)暴露一个函数允许获得返回值。

以下是返回专业化的示例(最后):

#include <iostream>
#include <functional>
#include <memory>


struct ACmd
{
  virtual void exec() = 0;
  virtual ~ACmd(){}
};

template <class F>
struct Cmd;

template <class R, class ... Args>
struct Cmd<R(Args...)> : ACmd
{
  R result_;
  std::function<R()> func_;

  template <class F>
  Cmd(F&& func, Args&&... args): result_(), func_()
  {
    auto f = std::bind(std::forward<F>(func), std::forward<Args>(args)...);
    func_ = [f](){
      return f();
    };
  }

  virtual void exec(){
    result_ = func_();
  }

  const R& getResult() const {return result_;}
};

// Make function for convenience, could return by value or ptr - 
//  - your choice
template <class R, class F, class ...Args>
Cmd<R(Args...)>* cmd(F&& func, Args&&... args)
{
  return new Cmd<R(Args...)>(func, std::forward<Args>(args)...);
}

//... And overload for void...

int foo(int arg) {
  return arg;   
}

int main() {

  auto x = cmd<int>(foo, 10);
  x->exec();
  std::cout << x->getResult() << std::endl;
  return 0;
}

答案 1 :(得分:1)

queue中每个元素的执行结果,void,您已经定义了它。如果传入的函数需要返回一个值,那么您需要限制返回到固定类型的类型,使用std::anystd::variant等实用程序或一些协变类型(可能)使用std::unique_ptrstd::shared_ptr)。

最简单的方法是修复返回类型(在编译时);

template <typename R>
using MQ = std::queue<std::function<R()>>;

MQ<int> q;

请参阅下面的示例。

队列声明需要是queue个对象,例如std::function个对象。 bind的返回值可以分配给function,然后按预期使用。

std::function是一个多态函数包装器,它实现类似于any的类型擦除模式,但是专门为函数和其他可调用对象设计。

通过example;

template <typename R>
using MQ = std::queue<std::function<R()>>;

MQ<int> q;

template<typename R,typename... ArgsT>
        void
        schedule(R&& fn, ArgsT&&... args)
        {
            q.push(std::bind(std::forward<R>(fn), std::forward<ArgsT>(args)...) );
        };

int main()
{   
    schedule([](int a) { std::cout << "function called" << std::endl; return a; }, 42);

    std::cout << q.front()() << std::endl;
}