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):
不幸的是,这意味着你甚至不能用std :: reference_wrapper替换引用,因为后者不是可移动的.我想使用std :: unique_ptr而不是引用将工作(这意味着,但是,你的函数参数将始终存在于堆上). (EDIT /校正) 如果你定义一个函数,它将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函数时,后者被自动转换为一个左值引用. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |