实现(可能是无效的)承诺

Bar*_*rry 15 c++ c++11

我正在编写一些多线程代码并使用promise/future在不同的线程上调用函数并返回其结果.为了简单起见,我将完全删除线程部分:

template <typename F>
auto blockingCall(F f) -> decltype(f()) 
{
    std::promise<decltype(f())> promise;

    // fulfill the promise
    promise.set_value(f());

    // block until we have a result
    return promise.get_future().get();
}
Run Code Online (Sandbox Code Playgroud)

这适用于任何返回非函数的函数void.获得未来的回报也适用于void.但如果f是一个void函数,我无法履行承诺,因为:

promise.set_value(F()); // 错误:无效使用void表达式

是否有一些聪明的方法在线上设置值void,或者我是否只需编写一个辅助函数,就像call_set_value(promise, f)有一个重载std::promise<R>std::promise<void>

Naw*_*waz 13

是.功能过载是最干净的解决方案:

set(promise, f);
Run Code Online (Sandbox Code Playgroud)

然后实现set为重载函数,如:

template<typename F, typename R>
void set(std::promise<R> & p, F && f) //handle non-void here
{
    p.set_value(f()); 
}

template<typename F>
void set(std::promise<void> & p, F && f)  //handle void here
{
    f();
    p.set_value(); 
}
Run Code Online (Sandbox Code Playgroud)


Jon*_*ely 13

A promise只是一种异步结果提供者.而不是promise你可以使用packaged_task包装可调用对象,而std::function不是调用它,除了调用它使得结果可以通过a future(当然它处理void和无效结果之间的差异):

template <typename F>
auto blockingCall(F f) -> decltype(f()) 
{
    std::packaged_task<decltype(f())()> task(std::move(f));

    task();

    // block until we have a result
    return task.get_future().get();
}
Run Code Online (Sandbox Code Playgroud)

NB根据目前的标准,该代码将有一个数据比赛中,如果task()task.get_future()发生在单独的线程(使用一个承诺,以便将原来的),所以你应该叫get_future()交给任务给其他线程之前.在实践中,它应该在实际实现中是安全的,并且存在库问题(LWG 2412)以使其无论如何都有效.