2012-12-11 17 views
11

पर बिल्कुल सही अग्रेषण मेरे पास एक फ़ंक्शन टेम्पलेट है, जहां मैं एक लैम्बडा में पूर्ण अग्रेषण करना चाहता हूं जिसे मैं किसी अन्य थ्रेड पर चलाता हूं। यहाँ एक न्यूनतम परीक्षण का मामला है जो आप सीधे संकलन कर सकते हैं:एसिंक लैम्ब्डा

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> >&’ 

मुझे लगता है:

#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; 
} 

गैर संकलन मामले के लिए, यहाँ त्रुटि संदेश जो सुगम है की अंतिम पंक्ति है यह T&& के साथ कुछ करने के लिए कुछ हो सकता है, लेकिन मैं विफलता के सटीक बिंदु को इंगित नहीं कर सकता और इसे ठीक कर सकता हूं। कोई सुझाव?

धन्यवाद!

संपादित करें: मैं बस मामले में जीसीसी 4.7.0 का उपयोग कर रहा है कि यह एक संकलक समस्या हो सकती है (शायद नहीं)

+0

मुझे यकीन नहीं है कि मैं सही हूं, लेकिन हो सकता है कि सी ++ के लिए आपको * प्रतिलिपि बनाने के लिए * स्पष्ट रूप से * std :: move' का उपयोग करें, जिसमें प्रतिलिपि और सेमेन्टिक्स दोनों स्थानांतरित हों। –

+0

क्षमा करें, मैंने सवाल अच्छी तरह से वाक्यांश नहीं दिया। मुझे संपादित करने दो। इसका संक्षेप में, यह है कि मैं काम करने के लिए दोनों कार्य तत्कालता चाहता हूं, और वे प्रत्येक एक अलग चीज करते हैं (प्रत्येक के आसपास एक संदर्भ पारित करके वेक्टर आगे बढ़ते हैं, दूसरी तरफ रावल्यू संदर्भ को आगे बढ़ाकर)। –

+0

यह पता चला है कि यह काम करता है यदि आप '(const std :: vector &) 'पर जाते हैं। –

उत्तर

7

तरह से मैं यह समझता हूं कि आप async के माध्यम से एक समारोह का उपयोग नहीं कर सकते हैं कि के रूप में गैर स्थिरांक lvalue संदर्भ उम्मीद तर्क, क्योंकि async हमेशा यह सुनिश्चित करने के लिए आंतरिक रूप से उनकी प्रतिलिपि बनाते हैं (या उन्हें अंदर ले जाते हैं) और बनाए गए थ्रेड के चलने वाले समय में मान्य होते हैं।

विशेष रूप से, मानक का कहना है async(launch policy, F&& f, Args&&... args) के बारे में:

(§30.6.8)

(2) आवश्यक है: F और Args में प्रत्येक Ti MoveConstructible आवश्यकताओं को पूरा करेगा। INVOKE(DECAY_COPY (std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...) (20.8.2, 30.3.1.2) एक मान्य अभिव्यक्ति होगी।

(3) प्रभाव: [...] अगर पॉलिसी & लांच :: async गैर-शून्य है - कॉल INVOKE(DECAY_COPY (std::forward<F>(f)),DECAY_COPY (std::forward<Args>(args))...) (20.8.2, 30.3.1.2) के रूप में यदि निष्पादन का एक नया सूत्र में एक धागा वस्तु का प्रतिनिधित्व करती DECAY_COPY() पर कॉल के साथ एसिंक नामक थ्रेड में मूल्यांकन किया जा रहा है। किसी भी वापसी मूल्य को साझा स्थिति में परिणाम के रूप में संग्रहीत किया जाता है। INVOKE (DECAY_COPY (std :: forward (f)), DECAY_COPY (std :: forward (args)) के निष्पादन से प्रचारित कोई भी अपवाद ...) साझा स्थिति में असाधारण परिणाम के रूप में संग्रहीत किया जाता है।
थ्रेड ऑब्जेक्ट साझा स्थिति में संग्रहीत है और किसी भी एसिंक्रोनस उस ऑब्जेक्ट को संदर्भित करने वाली वापसी ऑब्जेक्ट्स के व्यवहार को प्रभावित करता है।

दुर्भाग्य से, इसका मतलब है कि आप std::reference_wrapper के साथ संदर्भ को भी प्रतिस्थापित नहीं कर सकते हैं, क्योंकि बाद वाला स्थानांतरित नहीं होता है। मुझे लगता है कि संदर्भ के बजाय std::unique_ptr का उपयोग करना काम करेगा (हालांकि, यह कि आपके फ़ंक्शन तर्क हमेशा ढेर पर रहते हैं)।

(संपादित करें/सुधार)
मैं किसी समस्या से जूझ पर काम कर रहा था जब मुझे एहसास हुआ कि std::reference_wrapper वास्तव में, एक समाधान के लिए सक्षम बनाता है, हालांकि मैं विपरीत ऊपर का दावा किया।

आप एक समारोह है कि एक std::reference_wrapper में lvalue संदर्भ लपेटता है, लेकिन rvalue संदर्भ अपरिवर्तित छोड़ देता है परिभाषित हैं, तो आप std::async करने के लिए इसे सौंपने से पहले इस समारोह के माध्यम से T&& तर्क पारित कर सकते हैं।

#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 संकलन और काम के दोनों कॉल: मैं इस विशेष आवरण समारोह wrap_lval नीचे बुलाया। पहला, जो एक lvalue संदर्भ का उपयोग करता है, स्वचालित रूप से std::reference_wrapper में इसे लपेटता है। उत्तरार्द्ध स्वचालित रूप से एक lvalue संदर्भ में परिवर्तित हो जाता है जब std::async लैम्ब्डा फ़ंक्शन को कॉल करता है।

+0

धन्यवाद, समझ में आता है। मुझे लगता है कि क्षय प्रतिलिपि सुनिश्चित करता है कि संदर्भ नहीं मिलते हैं, और उन्हें "रक्षात्मक" प्रतिलिपि बनाते हैं। –