निम्नलिखित मेरा समाधान है जो एक को लैम्ब्स को लपेटने की अनुमति देता है (साथ ही किसी भी फ़ंक्शन ऑब्जेक्ट्स - यानी operator()
को कुछ भी कहा जा सकता है) प्रतिनिधियों में। इसमें कुछ सीमाएं हैं - विशेष रूप से, यह ट्रैकिंग संदर्भ पैरामीटर (%
सी ++/सीएलआई में ref
/out
सी #) में प्रतिनिधियों का समर्थन नहीं करती है; और प्रतिनिधि द्वारा प्राप्त किए जा सकने वाले मापदंडों की संख्या पर इसकी ऊपरी सीमा है (क्योंकि वीसी ++ 2010 वैरगा टेम्पलेट्स का समर्थन नहीं करता है) - हालांकि कोड जितना चाहें उतना समर्थन करने के लिए छोटे से समायोजित किया जा सकता है।
#pragma once
#include <new>
#include <type_traits>
namespace detail
{
struct return_type_helper
{
private:
template<class D>
struct dependent_false { enum { value = false }; };
template <class D>
struct illegal_delegate_type
{
static_assert(dependent_false<D>::value, "Delegates with more than 2 parameters, or with parameters of tracking reference types (T%), are not supported.");
};
struct anything
{
template<class T>
operator T() const;
};
public:
template<class D>
static decltype(static_cast<D^>(nullptr)()) dummy(int(*)[1]);
template<class D>
static decltype(static_cast<D^>(nullptr)(anything())) dummy(int(*)[2]);
template<class D>
static decltype(static_cast<D^>(nullptr)(anything(), anything())) dummy(int(*)[3]);
template <class D>
static illegal_delegate_type<D> dummy(...);
};
template<class Func, class Aligner = char, bool Match = (std::tr1::alignment_of<Func>::value == std::tr1::alignment_of<Aligner>::value)>
struct aligner
{
static_assert(Match, "Function object has unsupported alignment");
};
template<class Func, class Aligner>
struct aligner<Func, Aligner, true>
{
typedef Aligner type;
};
template<class Func>
struct aligner<Func, char, false> : aligner<Func, short>
{
};
template<class Func>
struct aligner<Func, short, false> : aligner<Func, int>
{
};
template<class Func>
struct aligner<Func, int, false> : aligner<Func, long>
{
};
template<class Func>
struct aligner<Func, long, false> : aligner<Func, long long>
{
};
template<class Func>
struct aligner<Func, long long, false> : aligner<Func, double>
{
};
template<class Func>
struct aligner<Func, double, false> : aligner<Func, void*>
{
};
template<class F>
ref class lambda_wrapper
{
public:
lambda_wrapper(const F& f)
{
pin_ptr<F> pf = (interior_ptr<F>)&f_storage;
new(pf) F(f);
}
~lambda_wrapper()
{
pin_ptr<F> pf = (interior_ptr<F>)&f_storage;
pf->~F();
}
template <class D>
operator D^()
{
D^ d = nullptr;
return gcnew D(this, &lambda_wrapper<F>::invoke<decltype(return_type_helper::dummy<D>(0))>);
}
private:
template<class T>
[System::Runtime::InteropServices::StructLayout(System::Runtime::InteropServices::LayoutKind::Sequential, Size = sizeof(T))]
value struct embedded_storage
{
private:
typename aligner<T>::type dummy;
};
embedded_storage<F> f_storage;
template<class R>
R invoke()
{
pin_ptr<F> pf = (interior_ptr<F>)&f_storage;
return (*pf)();
}
template<class R, class A1>
R invoke(A1 a1)
{
pin_ptr<F> pf = (interior_ptr<F>)&f_storage;
return (*pf)(a1);
}
template<class R, class A1, class A2>
R invoke(A1 a1, A2 a2)
{
pin_ptr<F> pf = (interior_ptr<F>)&f_storage;
return (*pf)(a1, a2);
}
};
}
template<class F>
detail::lambda_wrapper<F>^ make_delegate(F f)
{
return gcnew detail::lambda_wrapper<F>(f);
}
नमूना उपयोग:
Func<int, String^, int>^ f2 = make_delegate([&](int x, String^ y) -> int {
Console::WriteLine("Func {0} {1}", x, y);
return 2;
});
हालांकि यह तकनीकी रूप से आप क्या चाहते हैं करता है, व्यावहारिक अनुप्रयोगों के लिए कुछ हद तक इस तथ्य के कारण है कि C++ 0x lambdas सादा वर्गों में विस्तार कर रहे हैं, नहीं ref
या तक सीमित हैं value
वाले। चूंकि सादे वर्गों में सी ++/सीएलआई में प्रबंधित प्रकार नहीं हो सकते हैं (यानी ऑब्जेक्ट हैंडल प्रकार के कोई सदस्य नहीं, ट्रैकिंग संदर्भ प्रकार के कोई सदस्य नहीं हैं, और value class
प्रकार के कोई सदस्य नहीं हैं), इसका मतलब है कि लैम्बडा उन प्रकारों के किसी भी चर को कैप्चर नहीं कर सकता है। संदर्भों को ट्रैक करने के लिए मुझे कोई कामकाज नहीं है। value class
के लिए, आप इसे एक अप्रबंधित पॉइंटर ले सकते हैं (pin_ptr
यदि आवश्यक हो), और उसे कैप्चर करें।
ऑब्जेक्ट हैंडल के लिए, आप उन्हें gcroot<T>
में स्टोर कर सकते हैं, और इसे कैप्चर कर सकते हैं - लेकिन मेरे परीक्षणों में, gcroot<T>
के माध्यम से सदस्य तक पहुंचने से सादे ऑब्जेक्ट हैंडल का उपयोग करके इसे 40x गुना धीमा कर दिया जाता है। यह वास्तव में एक कॉल के लिए पूर्ण माप में बहुत अधिक नहीं है, लेकिन किसी लूप में बार-बार कहा जाता है - कहें, अधिकांश LINQ एल्गोरिदम - यह एक हत्यारा होगा। लेकिन ध्यान दें कि यह केवल तब लागू होता है जब आपको लैम्ब्डा में एक हैंडल कैप्चर करने की आवश्यकता होती है! यदि आप इसे एक अनुमानित इनलाइन लिखने के लिए या काउंटर अपडेट करने के लिए उपयोग करते हैं, तो यह ठीक काम करेगा।
यहां पोस्ट किया गया मेरा समाधान "Lambda2Delegate" जांचें http://stackoverflow.com/a/26552573/2604941 –