c – 完美转发到异步lambda

我有一个功能模板,我想做完美的转发到我在另一个线程上运行的lambda.这是一个最小的测试用例,您可以直接编译:
#include <thread>
#include <future>
#include <utility>
#include <iostream>
#include <vector>

/**
 * Function template that does perfect forwarding to a lambda inside an
 * async call (or at least tries to). I want both instantiations of the
 * function to work (one for lvalue references T&,and rvalue reference T&&).
 * However,I cannot get the code to compile when calling it with an lvalue.
 * See main() below.
 */
template <typename T>
std::string accessValueAsync(T&& obj)
{

    std::future<std::string> fut =
        std::async(std::launch::async,[](T&& vec) mutable
            {
                return vec[0];
            },std::forward<T>(obj));

    return fut.get();
}

int main(int argc,char const *argv[])
{
    std::vector<std::string> lvalue{"Testing"};

    // calling with what I assume is an lvalue reference does NOT compile
    std::cout << accessValueAsync(lvalue) << std::endl;

    // calling with rvalue reference compiles
    std::cout << accessValueAsync(std::move(lvalue)) << std::endl;

    // I want both to compile.

    return 0;
}

对于非编译的情况,这里是可理解的错误消息的最后一行:

main.cpp|13 col 29| note:   no kNown conversion for argument 1 from ‘std::vector<std::basic_string<char> >’ to ‘std::vector<std::basic_string<char> >&’

我有一种感觉,它可能与T&&被推断,但我无法确定确切的故障点并修复它.有什么建议么?

谢谢!

编辑:我正在使用gcc 4.7.0,以防这可能是一个编译器问题(可能不是)

解决方法

我理解的方式,你不能通过异步使用一个函数,期望非const lvalue引用作为参数,因为异步将始终在内部(或将它们移动到内部)中复制它们,以确保它们存在并且在整个运行时间内是有效的线程创建.

具体来说,该标准介绍了异步(发射政策,F&& F,Args& … args):

(§30.6.8)

(2) Requires: F and each Ti in Args shall satisfy the MoveConstructible requirements. INVOKE(DECAY_copY (std::forward<F>(f)),DECAY_copY (std::forward<Args>(args))...) (20.8.2,30.3.1.2) shall be a valid expression.

(3) Effects: […] if policy & launch::async is non-zero — calls INVOKE(DECAY_copY (std::forward<F>(f)),30.3.1.2) as if in a new thread of execution represented by a thread object with the calls to DECAY_copy() being evaluated in the thread that called async. Any return value is stored as the result in the shared state. Any exception propagated from the execution of INVOKE (DECAY_copY (std::forward(f)),DECAY_copY (std::forward(args))…) is stored as the exceptional result in the shared state.
The thread object is stored in the shared state and affects the behavior of any asynchronous
return objects that reference that state.

不幸的是,这意味着你甚至不能用std :: reference_wrapper替换引用,因为后者不是可移动的.我想使用std :: unique_ptr而不是引用将工作(这意味着,但是,你的函数参数将始终存在于堆上).

(EDIT /校正)
当我意识到std :: reference_wrapper实际上可以解决这个问题时,我正在处理一个相关的问题,尽管我声称相反.

如果你定义一个函数,它将lvalue引用包含在std :: reference_wrapper中,但是使rvalue引用不变,你可以通过T&&在通过此函数之前将其转换为std :: async.我已经在这里调用了这个特殊的wrapper函数wrap_lval:

#include <thread>
#include <future>
#include <utility>
#include <iostream>
#include <vector>
#include <type_traits>

/* First the two deFinitions of wrap_lval (one for rvalue references,the other for lvalue references). */

template <typename T>
constexpr T&&
wrap_lval(typename std::remove_reference<T>::type &&obj) noexcept
{ return static_cast<T&&>(obj); }

template <typename T>
constexpr std::reference_wrapper<typename std::remove_reference<T>::type>
wrap_lval(typename std::remove_reference<T>::type &obj) noexcept
{ return std::ref(obj); }


/* The following is your code,except for one change. */
template <typename T>
std::string accessValueAsync(T&& obj)
{

  std::future<std::string> fut =
    std::async(std::launch::async,[](T&& vec) mutable
           {
             return vec[0];
           },wrap_lval<T>(std::forward<T>(obj)));   // <== Passing obj through wrap_lval

  return fut.get();
}

int main(int argc,char const *argv[])
{
  std::vector<std::string> lvalue{"Testing"};

  std::cout << accessValueAsync(lvalue) << std::endl;

  std::cout << accessValueAsync(std::move(lvalue)) << std::endl;

  return 0;
}

有了这个变化,两个调用accessValueAsync都可以编译并工作.第一个使用了一个左值引用,自动将其包装在一个std :: reference_wrapper中.当std :: async调用lambda函数时,后者被自动转换为一个左值引用.

相关文章

本程序的编译和运行环境如下(如果有运行方面的问题欢迎在评...
水了一学期的院选修,万万没想到期末考试还有比较硬核的编程...
补充一下,先前文章末尾给出的下载链接的完整代码含有部分C&...
思路如标题所说采用模N取余法,难点是这个除法过程如何实现。...
本篇博客有更新!!!更新后效果图如下: 文章末尾的完整代码...
刚开始学习模块化程序设计时,估计大家都被形参和实参搞迷糊...