2013-07-15 9 views
16

मैं कुछ इस तरह करना चाहते हैं:पास लैम्ब्डा अभिव्यक्ति C++ 11

int main() 
{ 
    auto f = [/*some variables*/](/*take lambda function*/) 
    {/*something with lambda function*/}; 

    f([/*other variables*/](/*variables to be decided by f()*/) 
    {/*something with variables*/}); 
} 

मुझे पता है कि यह एक लैम्ब्डा के रूप में, एक समारोह के लिए एक लैम्ब्डा पारित करने के लिए और साथ ही संभव है। निम्नलिखित काम करता है:

int main() 
{ 
    int x=0; 
    int y=0; 
    auto f = [x,y](double (func)(int)) -> double 
    {func(0); return 0.0;}; 

    f([](int i) -> double 
    {return 0.0;}); 
} 

लेकिन निम्नलिखित काम नहीं करता है (जैसे ही मैं जोड़ने के लिए गुंजाइश चर बदलने के [x])

int main() 
{ 
    int x=0; 
    int y=0; 
    auto f = [x,y](double (func)(int)) -> double 
    {func(0); return 0.0;} 

    f([x](int i) -> double //[x] does not work 
    {return 0.0;}); 
} 

जो त्रुटि देता है:

error: function "lambda [](double (*)(int))->double::operator()" cannot be called with the given argument list 
     argument types are: (lambda [](int)->double) 
     object type is: lambda [](double (*)(int))->double 

किसी को भी इस बारे में कोई विचार होगा कि इसे कैसे ठीक किया जाए, या इसके आसपास एक तरीका? मैं एसटीडी के साथ इंटेल संकलक icpc (आईसीसी) 13.1.2 उपयोग कर रहा हूँ = C++ 11

धन्यवाद

+13

कैप्चरिंग लैम्ब्डा फ़ंक्शन पॉइंटर्स में परिवर्तनीय नहीं हैं –

+0

क्यों नहीं 'constexpr'? 'auto' एक संकलन-समय सुविधा है वैसे भी ... – user2485710

+4

@AndyProwl क्या? 10 मिनट के भीतर आप से कोई विस्तृत जवाब नहीं है? चलो, आप हमें यहां बहुत मेहनत करते हैं, और आपने दिन के लिए भी दोबारा तैयार नहीं किया है ;-) – TemplateRex

उत्तर

30

आपके प्रश्न के बारे में स्पष्टीकरण देने के लिए कुछ चीजें हैं। जिनमें से पहला लैम्ब्डा क्या है?

एक लैम्ब्डा अभिव्यक्ति एक साधारण अभिव्यक्ति है जिससे संकलक एक अद्वितीय प्रकार उत्पन्न करेगा जिसे नामित नहीं किया जा सकता है, और साथ ही यह प्रकार का एक उदाहरण उत्पन्न करेगा। जब आप लिखें: [](int i) { std::cout << i; } संकलक उत्पन्न होगा आपको लगता है कि के लिए एक प्रकार मोटे तौर पर है:

struct __lambda_unique_name { 
    void operator()(int i) const { std::cout << i; } 
}; 

आप देख सकते हैं, यह है नहीं एक समारोह है, लेकिन एक प्रकार है कि एक const सदस्य समारोह के रूप में operator() लागू करता है। यदि लैम्ब्डा ने कोई कैप्चर किया है, तो संकलक मूल्य/संदर्भों को कैप्चर करने के लिए कोड उत्पन्न करेगा।

एक कोने मामले के रूप में, इसके बाद के संस्करण है, जहां कोई राज्य पर कब्जा कर लिया जा रहा है की तरह lambdas के लिए, भाषा एक सूचक को लैम्ब्डा प्रकार से एक रूपांतरण operator() के हस्ताक्षर (ऋण this हिस्सा) के साथ कार्य करने के लिए के लिए अनुमति देता , इसलिए लैम्ब्डा ऊपर परोक्ष एक सूचक में बदला जा सकता int ले रहे हैं और कुछ भी नहीं लौटने कार्य करने के लिए:

void (*f)(int) = [](int i) { std::cout << i; } 

अब जब कि मूल बातें कहा गया है, अपने कोड में आप इस लैम्ब्डा है:

auto f = [x,y](double (func)(int)) -> double {func(0); return 0.0;}; 

फ़ंक्शंस के लिए पैरामीटर के नियम (जो लैम्बडास पर भी लागू होते हैं) यह निर्धारित करते हैं कि कोई तर्क फ़ंक्शन प्रकार का नहीं हो सकता है, इसलिए लैम्ब्डा के लिए तर्क कार्य करने के लिए पॉइंटर को डीक करता है (उसी तरह से टाइप सरणी का तर्क बाद में आप एक लैम्ब्डा एक तर्क के रूप में एक पर कब्जा किया है कि पारित करने के लिए कोशिश कर रहे हैं पर

auto f = [x,y](double (*func)(int)) -> double {func(0); return 0.0;}; 

: एक सूचक प्रकार के क्षय)। चूंकि एक कैप्चर होता है, विशेष नियम लागू नहीं होता है और लैम्ब्डा आपके द्वारा देखे गए कंपाइलर त्रुटि को उत्पन्न करने के लिए एक सूचक को परिवर्तनीय नहीं है।

वर्तमान मानक में आप दो तरीकों से जा सकते हैं। आप हस्ताक्षर से प्रतिदेय इकाई का सही प्रकार दूर करने के लिए टाइप-विलोपन का उपयोग कर सकते हैं:

auto f = [x,y](std::function<double(int)> func) -> double {func(0); return 0.0;}; 

क्योंकि एक std::function<double(int)> उचित हस्ताक्षर के साथ किसी भी प्रतिदेय इकाई के साथ प्रारंभ किया जा सकता है, इस में lambdas स्वीकार करेंगे नीचे दिए गए कोड, टाइप-एरर की लागत पर जो आमतौर पर एक गतिशील आवंटन और गतिशील प्रेषण का तात्पर्य है।

वैकल्पिक रूप से, आप सिंटैक्टिक चीनी छोड़ सकते हैं और पहले लैम्ब्डा को मैन्युअल रूप से समकक्ष रोल कर सकते हैं, लेकिन इसे सामान्य बना सकते हैं।

struct mylambda { 
    template <typename F> 
    double operator()(F fn) const { 
     fn(0); return 0.0; 
    } 
} f; 
// then use the non-lambda as you tried: 
f([x](int i) -> double {return 0.0;}); 

अंत में, यदि आपके पास पर्याप्त रोगी हैं, आप के लिए सी ++ 14, जहां (संभवत:, यह अभी तक नहीं किया गया है इंतज़ार कर सकते हैं: इस मामले में, जहां लैम्ब्डा सरल है में यह एक वैध विकल्प हो सकता है पुष्टि की) बहुरूपी lambdas जो ऊपर वर्ग के निर्माण को आसान बनाने के लिए समर्थन किया जाएगा:

auto f = [](auto fn) { fn(0.0); return 0.0; } // unrolls to 'mylambda' above 
+1

जो मैंने पढ़ा है, और [इस टिप्पणी] से भी (http://stackoverflow.com/questions/7951377/what-is-the-type-of-lambda-when-deduced-with-auto-in-c11#comment14872356_8050769) 'std :: function' टेम्पलेट तकनीक की तुलना में धीमी तंत्र है आप दिखाते हैं, हालांकि कुछ कहते हैं कि यह वर्चुअल कॉल के कारण है, जबकि आप कहते हैं कि यह गतिशील आवंटन के कारण है (हालांकि आप गतिशील प्रेषण भी कहते हैं जिसे मैं 'वर्चुअल' के समानार्थी मानता हूं)। सामान्यतः, आप अनुशंसा करते हैं कि आप टेम्पलेट? – johnbakers

5

std :: फ़ंक्शन का उपयोग करने का प्रयास करें:

#include <functional> 
int main() 
{ 
    int x=0; 
    int y=0; 
    auto f = [x,y](std::function<double(int)> func) -> double 
      {func(0); return 0.0;}; 

    f([x](int i) -> double {return 0.0;}); 
} 
+0

त्वरित प्रतिक्रिया के लिए धन्यवाद मैंने इसका उपयोग करने की कोशिश की है, लेकिन इंटेल कंपाइलर इसका समर्थन नहीं करता है [यहां] (http://stackoverflow.com/questions/6527064/stdfunction-and-the-intel-compiler-version-11-1)। बूस्ट/फ़ंक्शन लाइब्रेरी एक संभावित विकल्प हो सकता है, लेकिन मैं इसे आयात करने से बचने की कोशिश करना चाहता हूं।एक विकल्प क्या हो सकता है? – Couchy311

+1

अपने कंपाइलर को अपग्रेड/स्विच करें। आप कच्चे फ़ंक्शन पॉइंटर्स में चर को कैप्चर नहीं कर सकते हैं, इसके लिए आपको एक ऑब्जेक्ट चाहिए। यदि आपका कंपाइलर लैम्बडास प्रदान करता है लेकिन उन्हें स्टोर करने का कोई तरीका नहीं है (जो std :: function का मुख्य उद्देश्य है) IMHO आपको वास्तव में आपके कंपाइलर में लैम्ब्स के लिए समर्थन नहीं है। – DanielKO

+0

hmmm ... सच है, मुझे शायद लैम्ब्स के चारों ओर एक रास्ता मिलना चाहिए :( – Couchy311

1

आप की तरह कुछ की कोशिश कर सकते निम्नलिखित यदि आप पहले से लैम्ब्डा के प्रकार पता है, उदाहरण के लिए:

int main() 
{ 
    int x = 0, y = 0; 

    auto f = [x](int i)->double { 
     return (double)x; 
    }; 

    auto f2 = [x,y](decltype(f) func)->double { 
     return func(0); 
    }; 

    f2(f); 

    return 0; 
} 

या विकल्प आप के लिए <functional> पुस्तकालय इस्तेमाल कर सकते हैं रा अधिक सामान्य समाधान, उदाहरण के लिए:

auto f = [x,y](std::function<double(int)> func) { /* Do stuff */ }; 
3

आप बस गोली काटने और जैसे हम अंधेरे उम्र में किया था अपनी खुद की functors लागू करने के लिए हो सकता है:

struct F { 
    int x; 
    int y; 

    F(int x_, int y_) : x(x_), y(y_) {} 

    template <typename G> 
    double operator() (G&& g) const { 
     g(0); 
     return 0.0; 
    } 
}; 

#include <iostream> 

int main() 
{ 
    int x = 0; 
    int y = 0; 
    auto f = F(x, y); 

    f([x](int i){return 0.0;}); 
    f([](int i){std::cout << i << std::endl;}); 
} 

है कि आप जब तक जा रहा रखना चाहिए अपने कंपाइलर सी ++ 14 जेनेरिक लैम्बडा का समर्थन करता है।

+0

वहां एक रावल्यू संदर्भ का उपयोग करने का उद्देश्य या लाभ क्या है? (यानी '(जी और जी)' 'जी (जी जी)' से बेहतर है –

+1

@ChrisBecke अग्रेषण के बिना संदर्भ अग्रेषित करके पैरामीटर को स्वीकार करना "मैं इस तर्क को संभवतः उत्परिवर्तित करना चाहता हूं और मूल्य श्रेणी के लिए अनजान होना चाहता हूं।" – Casey

0

आप एक कैप्चरिंग लैम्ब्डा cify सकते हैं, लेकिन इस समाधान की अपनी सीमाएं हैं:

#include <new> 

#include <utility> 

namespace 
{ 

template <typename F, int I, typename L, typename R, typename ...A> 
inline F cify(L&& l, R (*)(A...) noexcept(noexcept(
    std::declval<F>()(std::declval<A>()...)))) 
{ 
    static L l_(std::forward<L>(l)); 
    static bool full; 

    if (full) 
    { 
    l_.~L(); 

    new (static_cast<void*>(&l_)) L(std::forward<L>(l)); 
    } 
    else 
    { 
    full = true; 
    } 

    return [](A... args) noexcept(noexcept(
     std::declval<F>()(std::forward<A>(args)...))) -> R 
    { 
     return l_(std::forward<A>(args)...); 
    }; 
} 

} 

template <typename F, int I = 0, typename L> 
inline F cify(L&& l) 
{ 
    return cify<F, I>(std::forward<L>(l), F()); 
} 


int main() 
{ 
    int x=0; 
    int y=0; 
    auto f = [x,y](double (func)(int)) -> double 
    {func(0); return 0.0;}; 

    f(cify<double(*)(int i)>([x](int i) -> double //works now 
    {return 0.0;})); 
} 
012 एक कामकाजी उदाहरण के लिए

Click

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