2017-08-29 199 views
2

我工作的一类,通过这样的队列中结合他们的时间表功能:如何使用标准库的std :: 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)...)); 
     }; 

正如你看到我在queuevoid()作出的类型,使其持有任何类型的函数对象,但现在当我执行它时,我无法得到回报。我该怎么做才能解决这个问题?

注:我不想使用像boost这样的外部库,我不知道用户会通过哪种函数。

+7

如果您不知道类型,您希望如何处理返回值? – Kevin

+0

在C++ 17或'boost :: any'中有'std :: any'。但似乎你不想使用它们中的任何一个。 – Rakete1111

+0

@Kevin这是队列中的类调度函数的一部分,并且同时执行它们,用户可以在函数执行完成之后获得返回值,所以我想要一些如何保存它以获取std :: future并返回它给用户 –

回答

3

注意:我不想使用像boost这样的外部库,我不知道用户会通过它的函数是什么类型。

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

这里是返回专业化(最后)的一个例子:

#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

每个元件在queue的执行的结果,它是void,已定义它是这样。如果传入的函数需要返回值,那么您需要将返回的类型限制为固定类型,使用实用程序(如std::any,std::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; 
} 
相关问题