Created
June 10, 2017 16:26
-
-
Save LYP951018/35a139877f1ea49d8e08280fadf1d87f to your computer and use it in GitHub Desktop.
Naive Bind
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 <type_traits> | |
#include <functional> | |
#include <tuple> | |
#include <utility> | |
#include <iostream> | |
#include <memory> | |
template<int I> | |
struct Placeholder | |
{ | |
inline static constexpr auto Value = I; | |
}; | |
inline static constexpr auto _1 = Placeholder<0>{}; | |
inline static constexpr auto _2 = Placeholder<1>{}; | |
template<typename T> | |
struct IsPlaceholder : std::false_type {}; | |
template<int I> | |
struct IsPlaceholder<Placeholder<I>> : std::true_type {}; | |
template<typename T> | |
struct IsReferenceWrapper : std::false_type {}; | |
template<typename T> | |
struct IsReferenceWrapper<std::reference_wrapper<T>> : std::true_type {}; | |
template<int I, typename... Args, typename... UArgs> | |
decltype(auto) Map(std::tuple<Args...>& args, [[maybe_unused]] std::tuple<UArgs...> uargs) | |
{ | |
using Type = std::tuple_element_t<I, std::tuple<Args...>>; | |
using DecayedType = std::decay_t<Type>; | |
if constexpr(IsPlaceholder<DecayedType>::value) | |
{ | |
return (std::get<DecayedType::Value>(uargs)); | |
} | |
else if constexpr(IsReferenceWrapper<DecayedType>::value) | |
{ | |
return std::get<I>(args).get(); | |
} | |
else | |
{ | |
return std::get<I>(args); | |
} | |
} | |
template<typename F, typename... Args> | |
struct Binder | |
{ | |
std::tuple<Args...> Parameters; | |
F Callable; | |
template<typename... UArgs> | |
decltype(auto) operator()(UArgs&&... uargs) | |
{ | |
return Impl(std::make_integer_sequence<int, sizeof...(Args)>{}, std::forward<UArgs>(uargs)...); | |
} | |
template<int... I, typename... UArgs> | |
decltype(auto) Impl(std::integer_sequence<int, I...>, UArgs&&... uargs) | |
{ | |
return std::invoke(Callable, Map<I>(Parameters, std::forward_as_tuple(std::forward<UArgs>(uargs)...))...); | |
} | |
}; | |
template<typename F, typename... Args> | |
Binder<std::decay_t<F>, std::decay_t<Args>...> Bind(F&& f, Args&&... args) | |
{ | |
return {{std::forward<Args>(args)...}, std::forward<F>(f)}; | |
} | |
void f(int n1, int n2, int n3, const int& n4, int n5) | |
{ | |
std::cout << n1 << ' ' << n2 << ' ' << n3 << ' ' << n4 << ' ' << n5 << '\n'; | |
} | |
int g(int n1) | |
{ | |
return n1; | |
} | |
struct Foo { | |
void print_sum(int n1, int n2) | |
{ | |
std::cout << n1+n2 << '\n'; | |
} | |
int data = 10; | |
}; | |
int main() | |
{ | |
int n = 7; | |
// (_1 and _2 are from std::placeholders, and represent future | |
// arguments that will be passed to f1) | |
auto f1 = Bind(f, _2, _1, 42, std::cref(n), n); | |
n = 10; | |
f1(1, 2, 1001); // 1 is bound by _1, 2 is bound by _2, 1001 is unused | |
// makes a call to f(2, 1, 42, n, 7) | |
Foo foo; | |
auto f3 = Bind(&Foo::print_sum, &foo, 95, _1); | |
f3(5); | |
// bind to a pointer to data member | |
auto f4 = Bind(&Foo::data, _1); | |
std::cout << f4(foo) << '\n'; | |
// smart pointers can be used to call members of the referenced objects, too | |
std::cout << f4(std::make_shared<Foo>(foo)) << '\n' | |
<< f4(std::make_unique<Foo>(foo)) << '\n'; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment