Skip to content

Instantly share code, notes, and snippets.

@kkspeed
Last active January 12, 2019 22:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kkspeed/01cf7978d574b0567ee8738aefc54510 to your computer and use it in GitHub Desktop.
Save kkspeed/01cf7978d574b0567ee8738aefc54510 to your computer and use it in GitHub Desktop.
C++ Possible Alternate Bind Implementation
// 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