2010-11-10 15 views
25

मुझे आश्चर्य हुआ है कि सी ++ 0x लैम्ब्डा को क्लैंग ब्लॉक में परिवर्तित करना संभव है या नहीं। अब तक मैंने जो कुछ भी देखा है, उसमें उनके मतभेदों के बीच चर्चा शामिल है। इसमें देखने के लिए मेरा प्राथमिक कारण है, libdispatch के लिए एक अंतिम आवरण बनाना है, और जब मुझे dispatch_*_f फ़ंक्शंस के बारे में पता है, तो उनके उपयोग के बारे में कोई भी जानकारी उनके ब्लॉक समकक्ष की तुलना में काफी कम है।क्या सी ++ 0x लैम्ब्डा को क्लैंग ब्लॉक में परिवर्तित करना संभव है?

अब तक मैं converting a C++ lambda to a function pointer पर जानकारी प्राप्त करने में सक्षम हूं, लेकिन यह रिवर्स के दायरे में अधिक है।

अगर कोई इससे संबंधित कुछ भी जानता है, और एक लिंक प्रदान कर सकता है, या कम से कम मुझे सही दिशा में इंगित कर सकता है, तो मैं वास्तव में इसकी सराहना करता हूं। (यहां तक ​​कि "यह वर्तमान में संभव नहीं है" उत्तर पर्याप्त होगा)

+0

बीटीडब्ल्यू, आपका शीर्षक लैम्ब्डा -> क्लैंग ब्लॉक को बदलने के लिए कहता है, लेकिन आपका प्रश्न ब्लॉक -> लैम्ब्डा को बदलने के लिए कहता है। –

+0

धन्यवाद, मैंने इसे अभी तय किया है :) –

उत्तर

12

इस रूपांतरण को सक्षम करने वाला एक पैच स्पष्ट रूप से क्लैंग ट्रंक में जोड़ा गया था।

+1

यूआरएल के साथ: [http://llvm.org/viewvc/llvm-project?view=rev&revision=150620 ](http://llvm.org/viewvc/llvm-project?view = rev & revision = 150620) –

+0

मैंने अभी क्लैंग वेबसाइट पर स्थित पृष्ठ देखा है जो बताता है कि यह कैसे काम करता है, इसलिए मैं इसे उत्तर के रूप में चिह्नित कर रहा हूं। –

2

मुझे नहीं लगता कि वास्तविक रूपांतरण संभव है। रिवर्स केस के विपरीत, मूल क्लैंग ब्लॉक से छुटकारा पाने के कुछ साइड इफेक्ट्स हैं जिन्हें आप पुनर्प्राप्त नहीं कर सकते हैं। जबकि C++ 0x lambdas संदर्भ द्वारा चर को कैप्चर कर सकता है, यह सुनिश्चित करने के लिए कुछ भी विशेष नहीं किया जाता है कि जब आप वास्तव में लैम्ब्डा का उपयोग करना चाहते हैं तो मूल चर अभी भी वहां है। दूसरी तरफ, ब्लॉक __block स्टोरेज क्वालीफायर के साथ घोषित चर के साथ बातचीत कर सकते हैं, इस मामले में इन चरों को स्मृति में रखा जाएगा (भले ही इसका मतलब स्टैक से ढेर तक कॉपी किया जा रहा हो) जब तक कि ब्लॉक रहता है (प्रतियां शामिल हैं Block_copy से):

__block चर भंडारण कि चर का शाब्दिक दायरा और सभी ब्लॉकों के बीच साझा किया और प्रतियां घोषित या चर का शाब्दिक दायरे के भीतर बनाया ब्लॉक है में रहते हैं। इस प्रकार, भंडारण स्टैक फ्रेम के विनाश जीवित रहने अगर ब्लॉक फ्रेम भीतर घोषित की कोई प्रति फ्रेम की समाप्ति के बाद जीवित रहने (उदाहरण के लिए, द्वारा बाद में निष्पादन के लिए कहीं कतारबद्ध जा रहा है) होगा।

इसलिए यदि आप मूल ब्लॉक के चारों ओर रखने के लिए करना चाहते हैं जब तक कि (और इस प्रकार परिवर्तित करने के बजाय लपेटकर), अपने मूल कार्यक्षमता के कुछ के रूप में __block चर चला जाएगा लापता कर दिया जाएगा।

हालांकि, मैं विषयों पर कोई विशेषज्ञ हूँ और दूसरों की राय :)

0

खैर, बजना अभी तक lambdas का समर्थन नहीं करता सुनवाई प्यार होता, और न तो एप्पल जीसीसी करता है। एफएसएफ जीसीसी हाल ही में लैम्बडास का समर्थन करने के लिए पर्याप्त है AFAIK ब्लॉक का समर्थन नहीं करते हैं। तो उनके बीच रूपांतरण का सवाल अभी तक लागू नहीं हुआ है।

एक बार क्लैंग इन दोनों का समर्थन करता है, तो ओब्जेसी ++ मोड में उनके बीच परिवर्तित करने का एक तरीका हो सकता है।

6

आम तौर पर, जब लैम्ब्डा के लिए "नीचे" बंद प्रयोग किया जाता है, तो आप परिवर्तित करके एक बजना ब्लॉक करने के लिए एक सी ++ लैम्ब्डा परिवर्तित कर सकते हैं:

[&](int i) { return i; } 

रहे हैं:

^(int i) { return i; } 

अभी भी कुछ सूक्ष्म है मतभेद। क्लैंग के ब्लॉक केवल कॉन्स द्वारा सी ++ कक्षाओं को पकड़ते हैं। मुझे नहीं पता कि इसमें सी ++ पीओडी प्रकार भी शामिल हैं या नहीं।

अंत में, यदि "ऊपर की ओर" बंद करने की आवश्यकता है, तो दोनों दो अलग-अलग हो जाते हैं।क्लैंग के ब्लॉक को __block के साथ एनोटेटेड वैरिएबल की आवश्यकता होती है, जो संकलक इसे ढेर पर आवंटित करेगा। जबकि, सी ++ में, लैम्ब्डा कैप्चर करने के तरीके को ऑब्जेक्ट के जीवनकाल के आधार पर तय करने की आवश्यकता होती है। (यह मूल्य प्रतिलिपि या संदर्भ द्वारा किया जाता है)।

सी ++ में, बंद करने की प्रतिलिपि स्वचालित रूप से सी ++ में कॉपी-कन्स्ट्रक्टर तंत्र द्वारा संभालती है। हालांकि, क्लैंग के ब्लॉक के साथ, ब्लॉक की प्रतिलिपि को संभालने के लिए Block_copy और Block_release को कॉल करने की आवश्यकता है। इसे संभालने के लिए सी ++ में एक साधारण रैपर लिखा जा सकता है। उदाहरण के लिए:

typedef void (^simple_block)(void); 
class block_wrapper 
{ 
    simple_block block; 

public: 
    block_wrapper (const simple_block& x) 
    : block(Block_copy(x)) {} 

    void operator()() const 
    { 
    block(); 
    } 

    block_wrapper(const block_wrapper& rhs) 
    : block(Block_copy(rhs.block)) 
    {} 

    block_wrapper& operator=(const block_wrapper& rhs) 
    { 
    if (this != &rhs) 
    { 
     Block_release(this->block); 
     this->block = Block_copy(rhs.block); 
    } 
    return *this; 
    } 

    ~block_wrapper() 
    { 
    Block_release(this->block); 
    } 
}; 
0

मैं libdispatch फ़ंक्शंस के *_f संस्करणों का उपयोग करने की अनुशंसा करता हूं। सभी ब्लॉक संस्करणों को हुड के तहत फ़ंक्शन संस्करणों के संदर्भ में लागू किया गया है, और सी ++ टेम्पलेट लिखना कहीं अधिक आसान है जो एक फ़ंक्शन का उत्पादन करता है जो एक टेम्पलेट की तुलना में लैम्ब्डा ऑब्जेक्ट को कॉल करता है जो ब्लॉक बनाता है जो लैम्ब्डा ऑब्जेक्ट को कॉल करता है।

हालांकि, सी ++ लैम्बडास के लिए क्लैंग में समर्थन की वर्तमान कमी पूरी बात पर एक धब्बा फेंक सकती है।

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