मैं C ++ 11 में लैम्ब्डा (उसी प्रकार का) का वेक्टर क्यों नहीं बना सकता हूं?


88

मैं लैम्ब्डा का वेक्टर बनाने की कोशिश कर रहा था, लेकिन असफल रहा:

auto ignore = [&]() { return 10; };  //1
std::vector<decltype(ignore)> v;     //2
v.push_back([&]() { return 100; });  //3

# 2 लाइन तक, यह ठीक संकलन करता है । लेकिन लाइन # 3 संकलन त्रुटि देता है :

त्रुटि: 'std :: वेक्टर <main () :: <lambda () >> :: push_back (main () :: <lambda ()>)' को कॉल करने के लिए कोई मेल नहीं खाता

मुझे फंक्शन पॉइंट्स या वेक्टर ऑफ़ फंक्शन ऑब्जेक्ट्स का वेक्टर नहीं चाहिए। हालाँकि, फंक्शन ऑब्जेक्ट्स के वेक्टर जो वास्तविक लैम्ब्डा एक्सप्रेशन को बढ़ाते हैं, मेरे लिए काम करेंगे। क्या यह संभव है?


23
"मुझे फंक्शन पॉइंट्स या वेक्टर ऑफ़ फंक्शन ऑब्जेक्ट्स का वेक्टर नहीं चाहिए।" लेकिन आपने जो मांगा है। एक लैम्ब्डा है एक समारोह वस्तु।
निकोल बोलस

जवाबों:


135

यदि उनके पास एक ही हस्ताक्षर है तो हर मेमने का एक अलग प्रकार होता है । आपको एक रन-टाइम एन्कैप्सुलेटिंग कंटेनर का उपयोग करना चाहिए जैसे किstd::function कि आप ऐसा कुछ करना चाहते हैं।

उदाहरण के लिए:

std::vector<std::function<int()>> functors;
functors.push_back([&] { return 100; });
functors.push_back([&] { return  10; });

52
सौ-मैन डेवलपर टीम का प्रबंधन मेरे लिए एक बुरे सपने की तरह लगता है :)
जेरेमी फ्रेज़र

10
इसके अलावा, यह मत भूलिए कि कैप्चरलेस लैम्ब्डा ([] -स्टाइल) फंक्शन पॉइंटर्स में नीचा दिखा सकता है। इसलिए वह एक ही प्रकार के फ़ंक्शन पॉइंटर्स की एक सरणी संग्रहीत कर सकता है। ध्यान दें कि VC10 अभी तक इसे लागू नहीं करता है।
निकोल बोलस

वैसे, उन उदाहरणों में वैसे भी कैप्चर-कम का उपयोग नहीं किया जाना चाहिए? या यह आवश्यक है? - वैसे, कैप्चरलेस लैम्बडा टू फंक्शन पॉइंटर VC11 में सपोर्ट करता है। हालांकि यह परीक्षण नहीं किया।
9

2
क्या विभिन्न प्रकार के वेक्टर संग्रह कार्य करना संभव है? यानी इसे सीमित करने के बजाय std::function<int(), मैं विभिन्न फ़ंक्शन प्रोटोटाइप का उपयोग कर सकता हूं?
मनतत्त २१'१५ को

2
@manatttta क्या बात होगी? कंटेनरों में एक ही प्रकार की वस्तुओं को संग्रहीत करने, उन्हें व्यवस्थित करने और एक साथ हेरफेर करने के लिए मौजूद है। आप यह भी पूछ सकते हैं कि 'क्या मैं vectorस्टोरिंग दोनों बना सकता हूं std::functionऔर std::string?' और जवाब एक ही है: नहीं, क्योंकि यह इच्छित उपयोग नहीं है। आप कंटेनर में असमान चीजों को रखने के लिए पर्याप्त प्रकार के प्रदर्शन को करने के लिए एक 'भिन्न' शैली की कक्षा का उपयोग कर सकते हैं, जबकि उपयोगकर्ता के लिए 'वास्तविक' प्रकार निर्धारित करने के लिए एक विधि भी शामिल है और इसलिए क्या करना है (जैसे कैसे कॉल करें) चुनें प्रत्येक तत्व ... लेकिन फिर से, इतनी लंबाई में क्यों जाएं? क्या कोई वास्तविक तर्क है?
अंडरस्कोर_ड

40

सभी लंबोदर अभिव्यक्तियों का एक अलग प्रकार है, भले ही वे समान चरित्र-दर-वर्ण हों । आप वेक्टर में एक अलग प्रकार का लंबो (क्योंकि यह एक और अभिव्यक्ति है) को आगे बढ़ा रहे हैं, और यह स्पष्ट रूप से काम नहीं करेगा।

एक समाधानstd::function<int()> इसके बजाय एक वेक्टर बनाना है ।

auto ignore = [&]() { return 10; };
std::vector<std::function<int()>> v;
v.push_back(ignore);
v.push_back([&]() { return 100; });

दूसरे नोट पर, [&]जब आप कुछ भी कैप्चर नहीं कर रहे हों, तो इसका उपयोग करना अच्छा नहीं है।


14
()लैंबडास की जरूरत नहीं है कि कोई तर्क न लें।
पिल्ला

18

हालांकि दूसरों ने जो कहा है वह प्रासंगिक है, फिर भी लैम्ब्डा के वेक्टर की घोषणा करना और उसका उपयोग करना अभी भी संभव है, हालांकि यह बहुत उपयोगी नहीं है:

auto lambda = [] { return 10; };
std::vector<decltype(lambda)> vec;
vec.push_back(lambda);

तो, आप किसी भी संख्या में लैम्ब्डा को वहां स्टोर कर सकते हैं, इसलिए जब तक यह एक कॉपी / चाल है lambda!


जो वास्तव में उपयोगी हो सकता है यदि पुशबैक विभिन्न मापदंडों के साथ लूप में होता है। संभवतः आलसी मूल्यांकन उद्देश्यों के लिए।
महाउजय

7
नहीं, आप वेक्टर को सिर्फ फंक्शन ऑब्जेक्ट में नहीं डालते हैं .. तो यह एक ही लैम्ब्डा की सभी प्रतियों के साथ एक वेक्टर होगा
hariseldon78

16

यदि आपका लैम्ब्डा स्टेटलेस है, अर्थात, [](...){...}C ++ 11 इसे फंक्शन पॉइंटर में नीचा दिखाने की अनुमति देता है। सिद्धांत रूप में, एक C ++ 11 संगत संकलक इसे संकलित करने में सक्षम होगा:

auto ignore = []() { return 10; };  //1 note misssing & in []!
std::vector<int (*)()> v;     //2
v.push_back([]() { return 100; });  //3

4
रिकॉर्ड के auto ignore = *[] { return 10; };लिए ignoreएक बनाना होगा int(*)()
ल्यूक डेंटन

1
@ लिक, ओह कि सकल है! उन्होंने कब जोड़ा?
एमएसएन

3
खैर, चूंकि रूपांतरण फ़ंक्शन जो पहली जगह में फ़ंक्शन पॉइंटर लेने की अनुमति देता है explicit, ऐसा नहीं होना अनिवार्य है , एक लंबोदर अभिव्यक्ति को वैधता देना और रूपांतरण के परिणामस्वरूप सूचक को डीरफेर करना है। फिर उपयोग कर रहा हैauto उस रेफरेंस पॉइंटर में वापस जाता है। (उपयोग auto&या auto&&संदर्भ रखा होगा।)
ल्यूक डैंटन

आह ... परिणामी सूचक को हटा देना। यह समझ आता है। क्या लापता ()जानबूझकर या आकस्मिक था?
एमएसएन

जानबूझकर, लैम्ब्डा अभिव्यक्ति समतुल्य है (लेकिन दो अक्षर छोटे)।
ल्यूक डैंटन

6

आप एक लैंबडा जनरेटिंग फंक्शन (नवाज़ द्वारा सुझाए गए फिक्स के साथ अद्यतन) का उपयोग कर सकते हैं:

#include <vector>
#include <iostream>

int main() {
    auto lambda_gen = [] (int i) {return [i](int x){ return i*x;};} ;

    using my_lambda = decltype(lambda_gen(1));

    std::vector<my_lambda> vec;

    for(int i = 0; i < 10; i++) vec.push_back(lambda_gen(i));

    int i = 0;

    for (auto& lambda : vec){
        std::cout << lambda(i) << std::endl;
        i++;
    }
}

लेकिन मुझे लगता है कि आपने मूल रूप से इस बिंदु पर अपना वर्ग बनाया है। अन्यथा यदि लंबोदर के पास पूरी तरह से अलग-अलग कैप्यूट्रेस / आर्ग आदि हैं, तो आपको संभवतः एक टपल का उपयोग करना होगा।


इसे एक फ़ंक्शन में लपेटने के लिए अच्छा विचार है, lambda_genजो एक लैंबडा के बदले में हो सकता है। हालाँकि, auto a = lambda_gen(1);एक अनावश्यक कॉल करता है, जिसे अगर हम ऐसा लिखते हैं तो इससे बचा जा सकता है decltype(lambda_gen(1))
नवाज

हालांकि यह अभी भी एक अतिरिक्त कॉल नहीं करता है? इसके अलावा एक और मामूली बात यह है कि प्रश्न C ++ 11 में वर्णित है, इसलिए मुझे लगता है कि फ़ंक्शन के लिए एक अनुगामी रिटर्न प्रकार जोड़ना होगा।
एंटील्यूवियन जूल

नहीं। कुछ भी अंदर decltype है unevaluated तो कॉल वास्तव में नहीं किया जाता है,। साथ ही ऐसा ही मामला है sizeof। इसके अलावा, यह कोड C ++ 11 में भी काम नहीं करेगा, भले ही आप अनुगामी रिटर्न प्रकार जोड़ दें !!
नवाज़

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.