2013-07-31 15 views
7

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

क्या सी ++/सीएलआई कोड में नियोजित करने के लिए मानक वर्कअराउंड है?

class A { } 

class B 
{ 
    void Foo() 
    { 
     A a = new A(); 
     Func<A> aFunc =() => a; // Captures a 
    } 
} 

मैं

  • प्रत्येक चर मैं चाहता हूँ के लिए एक सदस्य चर बना सकते हैं: दूसरे शब्दों में मैं एक मानक पैटर्न मैं C++/CLI में इस्तेमाल कर सकते हैं सी # से निम्न कार्य करने के लिए देख रहा हूँ कब्जा, और फिर प्रतिनिधि में उस सदस्य चर का उपयोग करें। यह सामान्य मामले में काम नहीं करेगा क्योंकि आपके पास इस विधि के दो आमंत्रण हो सकते हैं जो अलग-अलग कब्जे वाले पर काम करना चाहते हैं, लेकिन यह आम मामले के लिए काम करेगा।
  • एक नेस्टेड क्लास बनाएं जो उसके सीटीओ में कैप्चरिंग करता है, और फिर प्रतिनिधि के रूप में इस नेस्टेड क्लास की विधि का उपयोग करें। यह सामान्य मामले में काम करना चाहिए, लेकिन इसका मतलब है कि हर बार जब मैं विभिन्न चरों को कैप्चर करना चाहता हूं तो मुझे घोंसला वाले वर्ग की आवश्यकता होती है।

प्रश्न: वहाँ ऊपर वाले से एक बेहतर विकल्प है, या कौन-सा विकल्प ऊपर आपका प्रिय दृष्टिकोण हो सकता है?

संबंधित प्रश्न:

उत्तर

2

आप एक सी # लैम्ब्डा के decompilation को देखें, तो आपको लगता है कि सी # संकलक के रूप में एक ही बात करता है देखेंगे आपका विकल्प # 2। एकल उपयोग कक्षाओं का एक गुच्छा बनाने के लिए यह परेशान है, लेकिन यही वह है जो मैं अनुशंसा करता हूं।

सी # लैम्ब्डा के साथ, जब यह नेस्टेड क्लास इंस्टेंस बनाता है, तो यह स्थानीय चर के बजाय हर जगह इसका उपयोग करता है। इसे ध्यान में रखें क्योंकि आप नेस्टेड क्लास का उपयोग करने वाली विधि लिखते हैं।

6

मैंने इस उद्देश्य के लिए Lamda2Delegate संरचना लिखी। वास्तव में यह किसी भी .net प्रतिनिधि को सी ++ 11 लैम्ब्डा को परिवर्तित करता है।

उपयोग के उदाहरण:

Thread^ TestLambaWrapper() 
    { 
     gcroot<String ^> str = "Testext"; 
     int i = 12345; 
     Thread^ newThread = gcnew Thread(
      Lambda2Delegate<ParameterizedThreadStart>() = [&, str](Object^str2) 
      { 
       Sleep(2000); 
       Console::WriteLine("Thread output = {0} {1} {2}", str, i, str2); 
      } 
     ); 
     newThread->Start("Nahnah"); 
     return newThread; 
    } 

अपने मामले के लिए:

gcroot<A^> a = gcnew A(); 

    Func<A^>^aFunc = Lambda2Delegate<>() = [a](){ return (A^)a; }; 

    auto a2 = aFunc(); 

कामयाब कक्षाएं आप उन्हें gcroot के साथ रैप करने की जरूरत पर कब्जा करने के लिए, और मूल्य द्वारा स्पष्ट रूप से कब्जा।

और Lambda2Delegate।ज ही

#pragma once 
    #ifdef _MANAGED 

    struct AutoDetectDelegateType {}; 

    template<typename TDelegate, typename TLambda, typename TRet, typename ...TParams> 
    ref class LambdaHolder; 

    template<typename TDelegate, typename TLambda, typename TRet, typename ...TParams> 
    ref class LambdaHolder 
    { 
    public: 
     inline LambdaHolder(const TLambda % func) { m_func = new TLambda(func); } 
     !LambdaHolder() { delete m_func; } 
     ~LambdaHolder() { !LambdaHolder(); } 
    public: 
     TRet Callback(TParams... params) { return (*m_func)(params...); } 
     operator TDelegate ^() { return gcnew TDelegate(this, &LambdaHolder::Callback); } 
    private: 
     TLambda * m_func; 
    }; 

    template<typename TLambda, typename TRet, typename ...TParams> 
    ref class LambdaHolder<AutoDetectDelegateType, TLambda, TRet, TParams...> 
    { 
    public: 
     inline LambdaHolder(const TLambda % func) { m_func = new TLambda(func); } 
     !LambdaHolder() { delete m_func; } 
     ~LambdaHolder() { !LambdaHolder(); } 
    public: 
     TRet Callback(TParams... params) { return (*m_func)(params...); } 
     template<typename TDelegate> 
     operator TDelegate ^() { return gcnew TDelegate(this, &LambdaHolder::Callback); } 
    private: 
     TLambda * m_func; 
    }; 

    template <typename TDelegate, typename TLambda> 
    struct get_labmda_holder : public get_labmda_holder < TDelegate, decltype(&TLambda::operator()) > {}; 

    template <typename TDelegate, typename TLambda, typename TRet, typename... TParams> 
    struct get_labmda_holder < TDelegate, TRet(__clrcall TLambda::*)(TParams...) const > 
    { 
     typedef LambdaHolder<TDelegate, TLambda, TRet, TParams...> TLambdaHolder; 
    }; 

    template <typename TDelegate, typename TLambda, typename TRet, typename... TParams> 
    struct get_labmda_holder < TDelegate, TRet(__clrcall TLambda::*)(TParams...) > 
    { 
     typedef LambdaHolder<TDelegate, TLambda, TRet, TParams...> TLambdaHolder; 
    }; 

    template <typename TDelegate, typename TLambda, typename TRet, typename... TParams> 
    struct get_labmda_holder < TDelegate, TRet(__thiscall TLambda::*)(TParams...) const > 
    { 
     typedef LambdaHolder<TDelegate, TLambda, TRet, TParams...> TLambdaHolder; 
    }; 

    template <typename TDelegate, typename TLambda, typename TRet, typename... TParams> 
    struct get_labmda_holder < TDelegate, TRet(__thiscall TLambda::*)(TParams...)> 
    { 
     typedef LambdaHolder<TDelegate, TLambda, TRet, TParams...> TLambdaHolder; 
    }; 

    template<typename TDelegate = AutoDetectDelegateType> 
    struct Lambda2Delegate 
    { 
     template<typename TLambda> 
     typename get_labmda_holder<TDelegate, TLambda>::TLambdaHolder^operator = (const TLambda % func) 
     { 
      return gcnew get_labmda_holder<TDelegate, TLambda>::TLambdaHolder(func); 
     } 
    }; 

    #endif 

अद्यतन: यह कामयाब सदस्य समारोह के अंदर C++ लैम्ब्डा समारोह की घोषणा करने के लिए संभव नहीं है, लेकिन वैकल्पिक हल नहीं है - स्थिर सदस्य समारोह का उपयोग करें:

ref class S 
    { 
    public:  
     int F(System::String^str) 
     { 
      return F(this, str); 
     } 
    private: 
     //static function declaring c++ lambda 
     static int F(S^pThis, System::String^str) 
     { 
      gcroot<System::String ^> localStr = "local string"; 
      System::Func<System::String ^, int>^func = Lambda2Delegate<>() = [=](System::String^str) 
      { 
       System::Console::WriteLine(str); 
       System::Console::WriteLine(localStr); 
       return str->Length; 
      }; 
      return func(str); 
     } 
    }; 
+0

यह बहुत अच्छा है। धन्यवाद –

+0

मैं विजुअल स्टूडियो 2012 के साथ Lambda2Delegate.h का निर्माण नहीं कर सकता। विविध टेम्पलेट्स के साथ समस्या: 'त्रुटि C2143: वाक्यविन्यास त्रुटि: अनुपलब्ध', 'पहले' ... '\t ' – slater

+0

समस्या मिली http://stackoverflow.com/ प्रश्न/13238408/variadic-template-in-vs-2012-visual-c-november-2012-ctp – slater

3

इस में lambdas से निपटने के लिए मेरे समाधान है सी ++/सीएलआई, एक सुंदर सीधा वाक्यविन्यास के साथ। मैंने सोचा था कि किसी और इसे उपयोगी पाते हो सकता है:

struct DefaultDelegate; 

template<typename... Args> 
value struct DelegateType; 

template<typename Ret, typename... Args> 
value struct DelegateType<DefaultDelegate, Ret, Args...> 
{ 
    delegate Ret MyDelegate(Args...); 
    typedef MyDelegate delegate_type; 
}; 

template<typename Target, typename Ret, typename... Args> 
value struct DelegateType<Target, Ret, Args...> 
{ 
    typedef Target delegate_type; 
}; 

template<typename Lambda> 
ref class LambdaWrapper 
{ 
public: 
    LambdaWrapper(Lambda &&lambda) : func(new Lambda(std::forward<Lambda>(lambda))) {} 
    !LambdaWrapper() { delete func; } 
    ~LambdaWrapper() { delete func; } 
    template<typename Ret, typename... Args> 
    Ret CallLambda(Args... args) { return (*func)(args...); } 
private: 
    Lambda *func; 
}; 

template<typename Target, typename Lambda, typename Ret, typename... Args> 
auto _toDelegate(Lambda &&lambda, Ret(Lambda::*func)(Args...)) 
{ 
    LambdaWrapper<Lambda> ^lw = gcnew LambdaWrapper<Lambda>(std::forward<Lambda>(lambda)); 
    return gcnew typename DelegateType<Target, Ret, Args...>::delegate_type(lw, &LambdaWrapper<Lambda>::CallLambda<Ret, Args...>); 
} 

template<typename Target, typename Lambda, typename Ret, typename... Args> 
auto _toDelegate(Lambda &&lambda, Ret(Lambda::*func)(Args...) const) 
{ 
    LambdaWrapper<Lambda> ^lw = gcnew LambdaWrapper<Lambda>(std::forward<Lambda>(lambda)); 
    return gcnew typename DelegateType<Target, Ret, Args...>::delegate_type(lw, &LambdaWrapper<Lambda>::CallLambda<Ret, Args...>); 
} 

template<typename Target, typename Lambda> 
auto toDelegate(Lambda &&lambda) 
{ 
    return _toDelegate<Target>(std::forward<Lambda>(lambda), &Lambda::operator()); 
} 

उपयोग:

int k = 2; 
//If you need a generic delegate 
Delegate ^d = toDelegate<DefaultDelegate>([k](int i, int j) ->int {return k * (i + j); }); 
//If you need a delegate of a specific type 
MyDelegate ^d = toDelegate<MyDelegate>([k](int i, int j) ->int {return k * (i + j); }); 
संबंधित मुद्दे