2017-08-17 7 views
17

मैं इस तरह एक समारोह की घोषणा करना चाहते हैं:मैं सी ++ में नल लैम्ब्डा का उपयोग कैसे कर सकता हूं?

template <typename Lambda> 
int foo(Lambda bar) { 
    if(/* check bar is null lambda */) 
     return -1; 
    else 
     return bar(3); 
} 

int main() { 
    std::cout << foo([](int a)->int{return a + 3;}) << std::endl; 
    std::cout << foo(NULL_LAMBDA) << std::endl; 
} 

फिर, मैं कैसे NULL_LAMBDA और हालत की जाँच के पारित कर दिया लैम्ब्डा समारोह चाहे रिक्त है घोषणा कर सकते हैं?

+19

क्या आप "शून्य लैम्ब्डा" द्वारा मतलब है? – melpomene

+1

क्या आप 'std :: वैकल्पिक' या किसी अन्य लाइब्रेरी से समकक्ष का उपयोग कर सकते हैं? – KABoissonneault

उत्तर

26

आप एक समर्पित विशेषज्ञता जोड़ सकते हैं: इस विशेष मामले में

#include <iostream> 
#include <cstddef> 

template<typename Lambda> int 
foo(Lambda bar) 
{ 
    return(bar(3)); 
} 

template<> int 
foo<::std::nullptr_t>(::std::nullptr_t) 
{ 
    return(-1); 
} 

int main() 
{ 
    ::std::cout << foo([] (int a) -> int {return(a + 3);}) << ::std::endl; 
    ::std::cout << foo(nullptr) << ::std::endl; 
} 
+0

क्या कोई टेम्पलेट विशेषज्ञता बनाम गैर-टेम्पलेट अधिभार के लिए कोई लाभ है जो 'nullptr_t' लेता है? – LWimsey

+3

@LWimsey टेम्पलेट विशेषज्ञता होने से टेम्पलेट तर्क स्पष्ट रूप से प्रदान किए जाने पर सही 'foo' को कॉल करना संभव हो जाएगा। – VTT

+1

कृपया यहां विशेषज्ञता का उपयोग न करें। यह सामान्य अधिभार होने पर कुछ भी नहीं जोड़ता है और यदि आप एक अलग ओवरलोड जोड़ते हैं तो केवल समस्याएं पैदा हो सकती हैं। – Barry

8

, तो आप सिर्फ एक है कि हमेशा रिटर्न -1 के रूप में अपने अशक्त बंद परिभाषित कर सकते हैं:

template <typename Lambda> 
int foo(Lambda bar) { 
    return bar(3); 
} 

#include <iostream> 
int main() { 
    auto const NULL_LAMBDA = [](int){ return -1; }; 
    std::cout << foo([](int a) {return a + 3;}) << std::endl; 
    std::cout << foo(NULL_LAMBDA) << std::endl; 
} 

संभावना है कि यदि आप रन-टाइम पर का चयन कर रहे हैं, जो कार्यान्वयन करने के लिए कार्यान्वयन करते हैं, फिर आप टेम्पलेट को तत्काल करने के बजाय std::function के साथ टाइप-मिटाने से काफी बेहतर हैं। और std::function को खाली होने की अनुमति है - इसे शून्य सूचक के विरुद्ध से और तुलना की जा सकती है।


यदि आप जानते हैं संकलन समय पर कि कुछ कॉल साइटों हमेशा 'अशक्त' लैम्ब्डा पारित करेंगे, तो आप कार्यान्वयन उचित रूप से विशेषज्ञ कर सकते हैं। स्पष्ट विकल्पों में foo() को एक संस्करण के साथ अधिभारित करना शामिल है जो bar तर्क नहीं लेता है, या bar पर कॉल करने योग्य नहीं होने पर इसे एक अलग कार्यान्वयन के साथ विशेषज्ञता प्रदान करता है।

हैं foo() के बहुत मंगलाचरण दोनों प्रकार के (शायद यह दुष्प्रभाव का एक बहुत है, और bar() एक कॉलबैक के रूप में प्रदान की जाती है?) के लिए आम है, तो आप std::is_same<> का उपयोग कर वैकल्पिक हिस्सा conditionalise करने में सक्षम हो सकता है। यह if constexpr की आवश्यकता है, के रूप में लैम्ब्डा नहीं प्रतिदेय bar(3) प्रकार है:

static auto const NULL_LAMBDA = nullptr; 

#include <type_traits> 
template <typename Lambda> 
int foo(Lambda bar) { 
    if constexpr (std::is_same<decltype(bar), std::nullptr_t>::value) 
     return -1; 
    else 
     return bar(3); 
} 

#include <iostream> 
int main() { 
    std::cout << foo([](int a) {return a + 3;}) << std::endl; 
    std::cout << foo(NULL_LAMBDA) << std::endl; 
} 
+2

लैम्ब्डास '==' का समर्थन नहीं करते हैं। जब तक दोनों पक्ष एक ही हस्ताक्षर के साथ कैप्चरलेस लैम्बडा नहीं होते हैं और आप एमएसवीसी का उपयोग नहीं कर रहे हैं। –

+2

मैं '==' बिल्कुल उल्लेख नहीं करता; यह कीड़े का विशालकाय कर सकता है। यह केवल फ़ंक्शन पॉइंटर में रूपांतरण फ़ंक्शन के कारण संकलित करता है (जिसके लिए दोनों पक्षों को कैप्चरलेस होना आवश्यक है)।और चूंकि प्रत्येक लैम्ब्डा अभिव्यक्ति एक नया अपूर्ण प्रकार बनाता है, यह बेहद भंगुर है: 'foo ([] (int) {return 0;}) '' NULL_LAMBDA' पथ को दबा सकता है या नहीं। –

2

lambdas प्रकार की एक श्रेणी, नहीं एक प्रकार है।

हम ऐसा कर सकते हैं:

struct null_callable_t{ 
    template<class...Ts> 
    constexpr void operator()(Ts&&...)const{} 
    explicit constexpr operator bool()const{return false;} 
    constexpr null_callable_t() {} 
    friend constexpr bool operator==(::std::nullptr_t, null_callable_t){ return true; } 
    friend constexpr bool operator==(null_callable_t, ::std::nullptr_t){ return true; } 
    friend constexpr bool operator!=(::std::nullptr_t, null_callable_t){ return false; } 
    friend constexpr bool operator!=(null_callable_t, ::std::nullptr_t){ return false; } 
}; 

constexpr null_callable_t null_callable{}; 

अब हमारे कोड हो जाता है:

template <typename Lambda> 
int foo(Lambda bar) { 
    if(!bar) 
    return -1; 
    else 
    return bar(3); 
} 

जो बहुत चालाक है:

std::cout << foo([](int a) {return a + 3;}) << std::endl; 
std::cout << foo(null_callable) << std::endl; 
संबंधित मुद्दे