Last active
January 12, 2019 22:19
-
-
Save kkspeed/01cf7978d574b0567ee8738aefc54510 to your computer and use it in GitHub Desktop.
C++ Possible Alternate Bind Implementation
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
// Alternative implementation of bind without using placeholders. | |
// usage: | |
// Given void func(int a, int b, int c); | |
// auto f = my_bind(func, 3, 2); | |
// Then f(5) is the same as func(3, 2, 5); | |
// Also if first parameter is a weak pointer, this bind does the | |
// weak check automatically. | |
// For weak check to work successfully, the function needs to have void | |
// return type. | |
#include <functional> | |
#include <memory> | |
namespace { | |
template <typename... Rest> struct IsCancellable : std::false_type {}; | |
template <typename T, typename... Rest> | |
struct IsCancellable<std::weak_ptr<T>, Rest...> : std::true_type {}; | |
template <typename F, typename T, typename... Args> struct BindObject { | |
template <typename... TArgs> | |
BindObject(F &&f, T &&t, TArgs &&... bounded_args) | |
: f_(std::move(f)), weak_ref_(t), | |
bounded_params_(std::forward<TArgs>(bounded_args)...) {} | |
template <typename... CallArgs> void operator()(CallArgs &&... args) { | |
call(std::make_index_sequence<sizeof...(Args)>{}, | |
std::forward<CallArgs>(args)...); | |
} | |
private: | |
template <std::size_t... I, typename... CallArgs> | |
auto call(std::index_sequence<I...>, CallArgs &&... args) { | |
auto weak = weak_ref_.lock(); | |
if (!weak) | |
return; | |
std::invoke(f_, weak.get(), std::get<I>(bounded_params_)..., | |
std::forward<CallArgs>(args)...); | |
} | |
F f_; | |
T weak_ref_; | |
std::tuple<Args...> bounded_params_; | |
}; | |
template <typename F, typename... Args> struct BindNormalObject { | |
template <typename... TArgs> | |
BindNormalObject(F &&f, TArgs &&... bounded_args) | |
: f_(std::move(f)), | |
bounded_params_(std::forward<TArgs>(bounded_args)...) {} | |
template <typename... CallArgs> void operator()(CallArgs &&... args) { | |
call(std::make_index_sequence<sizeof...(Args)>{}, | |
std::forward<CallArgs>(args)...); | |
} | |
private: | |
template <std::size_t... I, typename... CallArgs> | |
auto call(std::index_sequence<I...>, CallArgs &&... args) { | |
std::invoke(f_, std::get<I>(bounded_params_)..., | |
std::forward<CallArgs>(args)...); | |
} | |
F f_; | |
std::tuple<Args...> bounded_params_; | |
}; | |
template <typename F, typename T, typename... Rest> | |
auto bind_aux(std::true_type, F &&f, T &&t, Rest &&... rest) { | |
return BindObject<F, T, Rest...>(std::forward<F>(f), std::forward<T>(t), | |
std::forward<Rest>(rest)...); | |
} | |
template <typename F, typename... Rest> | |
auto bind_aux(std::false_type, F &&f, Rest &&... rest) { | |
return BindNormalObject<F, Rest...>(std::forward<F>(f), | |
std::forward<Rest>(rest)...); | |
} | |
} // namespace | |
template <typename F, typename... Args> auto my_bind(F &&f, Args &&... args) { | |
return bind_aux(IsCancellable<std::decay_t<Args>...>{}, std::forward<F>(f), | |
std::forward<Args>(args)...); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment