2014-11-26 4 views
6

द्वारा कैप्चर करें क्या संकलन समय की जानकारी के आधार पर एक लैम्ब्डा की कैप्चर विधि को सशर्त रूप से चुनना संभव है? उदाहरण के लिए ...सी ++ 14 लैम्ब्डा - सशर्त रूप से संदर्भ या मूल्य

auto monad = [](auto && captive) { 
    return [(?)captive = std::forward<decltype(captive)>(captive)](auto && a) { 
     return 1; 
    }; 
}; 

मैं संदर्भ द्वारा कब्जा चाहते हैं, तो decltype(captive) एक std::reference_wrapper है, और सब कुछ किसी और मूल्य द्वारा कब्जा कर लिया।

+1

'context_wrapper' का बिंदु नहीं है कि यह एक संदर्भ की तरह है, सिवाय इसके कि इसे किसी समस्या के बिना मूल्य से पारित किया जा सकता है? फिर * वह * टाइप करें जिसे आप संदर्भ द्वारा कैप्चर करना चाहते हैं? मूल्य से सबकुछ कैप्चर करने में क्या गड़बड़ है? – hvd

+0

@hvd मैं संदर्भ द्वारा 'context_wrapper' को कैप्चर नहीं करना चाहता, मैं संदर्भ द्वारा संदर्भित संदर्भ को कैप्चर करना चाहता हूं। संदर्भ रैपर एक संदर्भ की तरह होना सबसे अच्छा है, लेकिन चूंकि कॉल ऑपरेटर (उर्फ, "।" ऑपरेटर) ओवरलोड नहीं किया जा सकता है, यह दिन के अंत में बहुत बुरी तरह विफल रहता है। – pat

+0

स्पष्टीकरण के लिए धन्यवाद। यह और अधिक समझ में आता है। इसलिए यदि आप 'संदर्भ_वर्तक' हैं, तो आप संदर्भ द्वारा 'कैप्टिव' को कैप्चर नहीं करना चाहते हैं, तो आप संदर्भ के द्वारा 'captive.get() 'को कैप्चर करना चाहते हैं, है ना? – hvd

उत्तर

4

लैम्ब्डा कैप्चर प्रकार टेम्पलेट-निर्भर नामों द्वारा नियंत्रित नहीं किया जा सकता है।

template<class T> 
auto make_monad(T&& arg) { 
    return [captive = std::forward<T>(arg)](auto&& a) { 
     std::cout << __PRETTY_FUNCTION__ << " " << a << '\n'; 
     return 1; 
    }; 
} 

template<class T> 
auto make_monad(std::reference_wrapper<T> arg) { 
    return [&captive = static_cast<T&>(arg)](auto&& a) { 
     std::cout << __PRETTY_FUNCTION__ << " " << a << '\n'; 
     return 1; 
    }; 
} 

int main() { 
    auto monad = [](auto&& captive) { 
     return make_monad(std::forward<decltype(captive)>(captive)); 
    }; 

    int n = 1; 
    monad(1)(1); 
    monad(n)(2); 
    monad(std::ref(n))(3); 
} 

आउटपुट:

make_monad(T&&)::<lambda(auto:1&&)> [with auto:1 = int; T = int] 1 
make_monad(T&&)::<lambda(auto:1&&)> [with auto:1 = int; T = int&] 2 
make_monad(std::reference_wrapper<_Tp>)::<lambda(auto:2&&)> [with auto:2 = int; T = int] 3 

मैं नहीं करना चाहती

हालांकि, अगर आप एक ओवरलोड कार्य करने के लिए आंतरिक लैम्ब्डा बनाने सौंपने के द्वारा वांछित प्रभाव को प्राप्त कर सकता है संदर्भ द्वारा संदर्भ_प्रैपर को कैप्चर करें, मैं संदर्भ द्वारा संदर्भित संदर्भ को कैप्चर करना चाहता हूं। संदर्भ रैपर एक संदर्भ की तरह होना सबसे अच्छा है, लेकिन चूंकि कॉल ऑपरेटर (उर्फ, "।" ऑपरेटर) ओवरलोड नहीं किया जा सकता है, यह दिन के अंत में बहुत बुरी तरह विफल रहता है।

इस मामले में आपको std::reference_wrapper<T> के लिए कैप्चर प्रकार बदलने की आवश्यकता नहीं है। इसके बजाय, आप तर्क के किसी भी अन्य प्रकार की तरह मान द्वारा और उपयोग स्थल पर पहला तर्क खोलने यह कब्जा करने के लिए पसंद कर सकते हैं:

template<class T> T& unwrap(T& t) { return t; } 
template<class T> T& unwrap(std::reference_wrapper<T> t) { return t; } 

auto monad = [](auto && captive) { 
    return [captive](auto && a) {   // <--- Capture by value. 
     auto& captive_ref = unwrap(captive); // <--- Unwrap before usage. 
     return 1; 
    }; 
}; 
+1

प्रतिक्रिया के लिए धन्यवाद!मुझे पता है कि ऐसा करने के पुराने स्कूल के तरीके का एक समूह है, मैं उम्मीद कर रहा था कि सी ++ 14 समाधान में कुछ शव के लिए अनुमति देगा। – pat

+0

@Casey सबसे अधिक संभावना है, मूल सवाल, हालांकि, संदर्भ द्वारा रैपर को पकड़ना चाहता था। –

+0

@Casey अपडेट किया गया। –

1

यह अपने प्रश्न लेकिन अपनी टिप्पणी का उत्तर न मिले, कैसे operator . उपयोग करने के लिए:

आप उन दो भार के जोड़ सकते हैं:

template <typename T> 
T& get_reference_object(T&& t) { return t; } 

template <typename T> 
T& get_reference_object(std::reference_wrapper<T> t) { return t.get(); } 

और फिर आप अपने लैम्ब्डा के अंदर get_reference_object(arg).foo उपयोग कर सकते हैं:

auto monad = [](auto && captive) { 
    return [captive = captive](auto&& a) { return get_reference_object(captive).foo(a); }; 
}; 

Live example

संबंधित मुद्दे