微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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函数时,后者被自动转换为一个左值引用.

原文地址:https://www.jb51.cc/c/112367.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐