Last active
September 25, 2016 15:54
-
-
Save Garciat/06fec39ffb589783f889e234747fd33d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <functional> | |
#include <iostream> | |
#include <utility> | |
using namespace System; | |
using namespace System::Linq; | |
using namespace System::Collections::Generic; | |
template <typename T> | |
struct identity { using type = T; }; | |
template <typename F> | |
struct function_of : function_of<decltype(&F::operator())> {}; | |
template <typename C, typename R, typename... A> | |
struct function_of<R(C::*)(A...)> : identity<R(A...)> {}; | |
template <typename C, typename R, typename... A> | |
struct function_of<R(C::*)(A...) const> : identity<R(A...)> {}; | |
template <typename R, typename... A> | |
struct function_of<R(*)(A...)> : identity<R(A...)> {}; | |
template <typename R, typename... A> | |
struct function_of<R(A...)> : identity<R(A...)> {}; | |
template <typename F> | |
using function_of_t = typename function_of<F>::type; | |
template <typename...> | |
struct to_delegate; | |
template <typename R> | |
struct to_delegate<R> : identity<Func<R>> {}; | |
template <typename T1, typename R> | |
struct to_delegate<T1, R> : identity<Func<T1, R>> {}; | |
template <typename T1, typename T2, typename R> | |
struct to_delegate<T1, T2, R> : identity<Func<T1, T2, R>> {}; | |
template <typename... Ts> | |
using to_delegate_t = typename to_delegate<Ts...>::type; | |
template <typename> | |
ref struct DelegateHelper; | |
template <typename R, typename... A> | |
ref struct DelegateHelper<R(A...)> { | |
using delegate_type = to_delegate_t<A..., R>; | |
template <typename F> | |
DelegateHelper(F &&f) { | |
func = new std::function<R(A...)>(std::move(f)); | |
} | |
~DelegateHelper() { | |
this->!DelegateHelper(); | |
} | |
!DelegateHelper() { | |
if (func) { | |
delete func; | |
func = nullptr; | |
} | |
} | |
R Call(A... args) { | |
return (*func)(std::forward<A>(args)...); | |
} | |
auto ToDelegate() { | |
return gcnew delegate_type(this, &DelegateHelper::Call); | |
} | |
static operator delegate_type ^ (DelegateHelper ^helper) { | |
return helper->ToDelegate(); | |
} | |
private: | |
std::function<R(A...)> *func; | |
}; | |
template <typename F> | |
auto make_delegate(F &&f) { | |
// we leak `helper`. let the GC finalize it whenever... | |
auto helper = gcnew DelegateHelper<function_of_t<F>>(std::move(f)); | |
return helper->ToDelegate(); | |
} | |
void example(Func<int, int> ^f) { | |
Console::WriteLine(f(10)); | |
} | |
struct multiplier { | |
int operator()(int x) { | |
return x * k; | |
} | |
int k; | |
}; | |
int main(array<System::String ^> ^args) { | |
int z = 10; | |
example(make_delegate([z](int x) { return x * z; })); | |
example(make_delegate(multiplier{ 10 })); | |
example(gcnew DelegateHelper<int(int)>([](int x) { return x; })); | |
auto sum = make_delegate([](int a, int b) { return a + b; }); | |
Console::WriteLine(Enumerable::Aggregate(Enumerable::Range(0, 10), sum)); | |
Console::ReadKey(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment