2011-09-03 4 views
12

निर्धारित करने के लिए एक सीमा के एक तत्व होता है कि क्या निम्नलिखित खिलौना कोड पर विचार करें:मैं लैम्ब्डा के अंदर एक फ़ंक्शन से कैसे लौट सकता हूं?

template<typename Iter, typename T> 
bool contains1(Iter begin, Iter end, const T& x) 
{ 
    for (; begin != end; ++begin) 
    { 
     if (*begin == x) return true; 
    } 
    return false; 
} 

(हाँ मैं जानता हूँ कि, मानक पुस्तकालय में पहले से ही बिल्कुल ठीक एल्गोरिदम देखते हैं, उस बिंदु नहीं है।)

कैसे क्या मैं for_each और लैम्ब्डा के साथ एक ही चीज़ लिखूंगा? निम्नलिखित काम नहीं करता है ...

template<typename Iter, typename T> 
bool contains2(Iter begin, Iter end, const T& x) 
{ 
    std::for_each(begin, end, [&x](const T& y) { 
     if (x == y) return true; 
    }); 
    return false; 
} 

... क्योंकि यह केवल समारोह से नहीं, बल्कि लैम्ब्डा से वापस आएगा।

क्या मुझे लैम्ब्डा से बाहर निकलने के लिए अपवाद फेंकना है? फिर, इस विशिष्ट समस्या के लिए शायद एक दर्जन बेहतर समाधान हैं जिनमें लैम्ब्स शामिल नहीं हैं, लेकिन यह वह नहीं है जो मैं पूछ रहा हूं।

+1

आप इस तरह से लैम्ब्डा से वापस नहीं आ सकते हैं। लैम्ब्डा कंपाइलर के लिए है, एक और समारोह, कहीं और पारित किया जा सकता है। लैम्ब्डा को दूसरी विधि में पास करने के लिए यह मूर्खतापूर्ण होगा, जहां यह कॉल 2 स्तर तक कूद जाएगा, है ना? – nothrow

+3

यदि आप सभी तत्वों को संसाधित नहीं करना चाहते हैं तो आपको वास्तव में for_each का उपयोग नहीं करना चाहिए। –

+1

आप यह नहीं कर सकते हैं। आप कई अन्य तरीकों से एक ही प्रभाव प्राप्त कर सकते हैं। क्या आपके पास एक गैर-प्रदूषित उदाहरण है जहां यह वास्तव में सार्थक होगा? – Mankarse

उत्तर

7

मैं for_each और लैम्ब्डा के साथ एक ही चीज़ कैसे लिखूं?

आप (अपवाद छोड़कर) नहीं कर सकते हैं। आपका फ़ंक्शन प्रत्येक लूप (= मैपिंग की तरह) के लिए isomorphic नहीं है, यह उतना आसान है।

इसके बजाय, आपके फ़ंक्शन को कम करके वर्णित किया गया है ताकि यदि आप इसे बदलने के लिए उच्च-आदेश फ़ंक्शंस का उपयोग करना चाहते हैं, तो मानचित्र का उपयोग करें, कमी का उपयोग करें।

हैं सी ++ था एक उचित, सामान्य उद्देश्य reduce फिर अपने एल्गोरिथ्म के रूप में विचार करेंगे इस प्रकार है:

template<typename Iter, typename T> 
bool contains2(Iter begin, Iter end, const T& x) 
{ 
    return stdx::reduce(begin, end, [&x](const T& y, bool accumulator) { 
     return accumulator or x == y; 
    }); 
} 
बेशक

, यह केवल बाहर निकलता है जल्दी अगर कमी ठीक से बूलियन परिणाम मूल्यों के लिए विशेष है शॉर्ट-सर्किट के लिए।

अलास, सी ++ जहां तक ​​मैं देखता हूं ऐसी कार्यक्षमता प्रदान नहीं करता है। accumulate है लेकिन यह शॉर्ट-सर्किट नहीं होगा (यह नहीं कर सकता - सी ++ यह नहीं जानता कि ऑपरेशन के अंदर लैम्ब्डा शॉर्ट सर्किट है, और इसे पुनरावर्ती रूप से लागू नहीं किया गया है)।

+0

यदि आप शॉर्ट-सर्किट में सामान्य रूप से कार्यान्वयन को कम करना चाहते हैं तो आपको आलसी प्रकार की आवश्यकता होगी। – ysdx

+0

@ysdx आप मज़ेदार ('is_short_circuited') के लिए एक विशेषता का विशेषज्ञ हो सकते हैं। सुरुचिपूर्ण लेकिन सामान्य उद्देश्य के रूप में नहीं। –

0

इस संदर्भ में, लैम्ब्डा किसी भी अन्य फ़ंक्शन की तरह है जिसे दिए गए फ़ंक्शन contains2() से कहा जाता है। अन्य फ़ंक्शन से लौटने का मतलब यह नहीं है कि आप दिए गए फ़ंक्शन से वापस आ रहे हैं। इस प्रकार यह संभव नहीं है और इस तरह डिज़ाइन जाना चाहिए।

दिए गए उदाहरण जैसे पैटर के लिए, अपवाद फेंकना अनावश्यक ओवरहेड है। मैं return के बजाय लैम्ब्डा के अंदर bool चर सेट करता हूं (और begin = end; भी सेट करता हूं)। दिए गए फ़ंक्शन contains2() से लौटने के लिए यह bool चेक किया जा सकता है।

+0

बूल सेटिंग को छोड़कर इसका मतलब है कि शेष अनुक्रम को फिर से चालू किया जाएगा, जबकि अपवाद फेंकने से पुनरावृत्ति समाप्त हो जाएगी। अनुक्रम के आकार के आधार पर, अपवाद फेंकने की संभावना तेज हो सकती है (फिर फिर, मुझे प्रदर्शन मामलों पर शक है, क्योंकि यह स्पष्ट रूप से सिर्फ एक खिलौना "क्या-अगर" उदाहरण है। – jalf

+0

@jalf, हम 'start = end' भी सेट कर सकते हैं ; 'लैम्ब्डा फ़ंक्शन के अंदर शेष अनुक्रम को पुन: सक्रिय करने से बचने के लिए। – iammilind

+0

आप कोशिश कर सकते हैं। लेकिन यह मानता है कि' for_each 'आंतरिक रूप से उन इटरेटर्स की प्रतिलिपि नहीं करेगा। – jalf

7

std::for_each एल्गोरिदम नहीं है यदि आप लूप को जल्दी समाप्त करना चाहते हैं तो आपको इसका उपयोग करना चाहिए। ऐसा लगता है कि आप std::find_if या कुछ समान चाहते हैं। आपको उस एल्गोरिदम का उपयोग करना चाहिए जो आपके कार्य के लिए सबसे उपयुक्त है, न केवल उस व्यक्ति से जिसे आप परिचित हैं।


तुम सच में, वास्तव में, वास्तव में जल्दी एक एल्गोरिथ्म से "लौटने" चाहिए, आप कर सकता हूँ- यदि

चेतावनी: क्या इस प्रकार है एक बहुत, वास्तव में बुरा विचार और आपको वस्तुतः ऐसा कभी नहीं करना चाहिए। दरअसल, कोड को देखकर आपका चेहरा पिघल सकता है। आपको चेतावनी दी गई है!

फेंक एक अपवाद: - कम से कम जब यह प्रवाह है, जो यहाँ क्या मायने रखती है नियंत्रित करने के लिए आता है

bool contains2(Iter begin, Iter end, const T& x) 
{ 
    try { 
    std::for_each(begin, end, [&x](const T& y) { 
     if (x == y) 
      throw std::runtime_error("something"); 
    }); 
    } 
    catch(std::runtime_error &e) { 
    return true; 
    } 
    return false; 
} 
+6

आप मूल रूप से केवल प्रश्न चिह्न के बिना प्रश्न को दोहरा रहे हैं। * ने कहा * वह जानता है कि अधिक उपयुक्त 'std' एल्गोरिदम हैं, और उन्होंने अपवाद फेंकने की संभावना का उल्लेख किया। – jalf

+1

-1 क्या जल्फ ने कहा – IronMensan

2

lambdas क्योंकि वे काफी हद तक काम करता है की तरह व्यवहार अमूर्त की गलत स्तर हैं। आप कुछ फ़ंक्शन (या प्रक्रियात्मक प्रोग्रामिंग की प्रक्रियाओं) के रूप में 'encapsulated' के रूप में कुछ नहीं चाहते हैं, जो सी ++ में या तो सीधे वापसी या अपवाद फेंक सकता है। इस व्यवहार को कम करने के किसी भी प्रयास को मेरी राय में पैथोलॉजिकल माना जाना चाहिए - या कम से कम एक प्रक्रिया के रूप में मास्कराइड नहीं करना चाहिए।

निष्पादन के प्रवाह के बेहतर नियंत्रण के लिए, कोरआउट जैसे कुछ अमूर्तता और/या आदिम के बेहतर उपयुक्त स्तर हो सकते हैं। फिर भी, मुझे डर है कि अंतिम परिणाम std::for_each का उपयोग करने जैसा कुछ नहीं दिखता है।

2

एक कस्टम एल्गोरिथ्म का उपयोग करें:

template<class I, class F> 
bool aborting_foreach(I first, I last, F f) { 
    while(;first!=last;++first) { 
    if(!f(*first)) 
     return false;  
    } 
    return true; 
} 

ठीक है, इस तथ्य को std :: all_of में है, लेकिन आप विचार मिलता है। ("कमी जवाब" देखें)।

// Optional A value 
template<class A> 
class maybe { 
    // ... 
}; 

या

// Stores either a A result of a B "non local return" 
template<class A, class B> 
class either { 
    … 
}; 

इसी हास्केल प्रकार देखें: अपने कार्य कुछ प्रकार वापस जाने के लिए की जरूरत है, तो आप किसी भिन्न रूप प्रकार का उपयोग कर सकते हैं। आप इसे साफ करने के लिए सी ++ 01 "अप्रतिबंधित संघ" का उपयोग कर सकते हैं।

गैर-स्थानीय निकास करने का एक साफ तरीका निरंतरता का उपयोग कर रहा है लेकिन आपके पास उन्हें C++ में नहीं है।

0

जैसा कि आपने और अन्य ने for_each को इंगित किया है, यहां उपयोग करने के लिए सही एल्गोरिदम नहीं है। for_each लूप से बाहर निकलने का कोई तरीका नहीं है - अपवाद को छोड़कर (इच्छित इरादा) - आपको इसे पूरी तरह से चलाने के लिए है।

template<typename Iter, typename T> 
bool contains2(Iter begin, Iter end, const T& x) 
{ 
    bool tContains = false; 
    std::for_each(begin, end, [&](const T& y) mutable { 
     tContains = tContains || x == y; 
    }); 
    return tContains; 
} 
1

std::any_of का उपयोग करें।

template<typename Iter, typename T> 
bool contains2(Iter begin, Iter end, const T& x) 
{ 
    const bool contains = std::any_of(begin, end, [&x](const T& y) 
    { 
     return x == y; 
    }); 

    return contains; 
} 
संबंधित मुद्दे

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