15 #ifndef TLX_DELEGATE_HEADER
16 #define TLX_DELEGATE_HEADER
22 #include <type_traits>
27 template <
typename T,
typename Allocator = std::allocator<
void> >
90 template <
typename R,
typename... A,
typename Allocator>
113 template <R(*
const Function)(A...)>
115 return Delegate(function_caller<Function>,
nullptr);
124 explicit Delegate(R(*
const function_ptr)(A...)) noexcept
126 *reinterpret_cast<
void* const*>(&function_ptr)) { }
128 static_assert(
sizeof(
void*) ==
sizeof(
void (*)(
void)),
129 "object pointer and function pointer sizes must equal");
132 static Delegate make(R(*
const function_ptr)(A...)) noexcept {
142 template <
class C, R(C::*
const Method)(A...)>
143 static Delegate make(C*
const object_ptr) noexcept {
144 return Delegate(method_caller<C, Method>, object_ptr);
148 template <
class C, R(C::*
const Method)(A...)
const>
149 static Delegate make(C
const*
const object_ptr) noexcept {
150 return Delegate(const_method_caller<C, Method>,
151 const_cast<C*
>(object_ptr));
156 template <
class C, R(C::*
const Method)(A...)>
157 static Delegate make(C&
object) noexcept {
158 return Delegate(method_caller<C, Method>, &
object);
163 template <
class C, R(C::*
const Method)(A...)
const>
164 static Delegate make(C
const&
object) noexcept {
165 return Delegate(const_method_caller<C, Method>,
166 const_cast<C*
>(&
object));
178 typename =
typename std::enable_if<
179 !std::is_same<Delegate, typename std::decay<T>::type>::value
185 typename Allocator::template rebind<
186 typename std::decay<T>::type>::other().allocate(1),
187 store_deleter<typename std::decay<T>::type>, Allocator()) {
189 using Functor =
typename std::decay<T>::type;
190 using Rebind =
typename Allocator::template rebind<Functor>::other;
194 static_cast<Functor*
>(store_.get()), Functor(std::forward<T>(f)));
196 object_ptr_ = store_.get();
198 caller_ = functor_caller<Functor>;
203 template <
typename T>
205 return std::forward<T>(f);
210 Delegate(C*
const object_ptr, R(C::*
const method_ptr)(A...))
211 : Delegate(MemberPair<C>(object_ptr, method_ptr)) { }
215 Delegate(C*
const object_ptr, R(C::*
const method_ptr)(A...)
const)
220 Delegate(C&
object, R(C::*
const method_ptr)(A...))
221 :
Delegate(MemberPair<C>(&object, method_ptr)) { }
225 Delegate(C
const&
object, R(C::*
const method_ptr)(A...)
const)
230 static Delegate make(C*
const object_ptr,
231 R(C::*
const method_ptr)(A...)) {
238 R(C::*
const method_ptr)(A...)
const) {
244 static Delegate make(C&
object, R(C::*
const method_ptr)(A...)) {
250 static Delegate make(C
const&
object,
251 R(C::*
const method_ptr)(A...)
const) {
261 void reset() { caller_ =
nullptr; store_.reset(); }
263 void reset_caller() noexcept { caller_ =
nullptr; }
269 bool operator == (Delegate
const& rhs)
const noexcept {
270 return (object_ptr_ == rhs.object_ptr_) && (caller_ == rhs.caller_);
280 return (object_ptr_ < rhs.object_ptr_) ||
281 ((object_ptr_ == rhs.object_ptr_) && (caller_ < rhs.caller_));
285 bool operator == (std::nullptr_t
const)
const noexcept {
286 return caller_ ==
nullptr;
290 bool operator != (std::nullptr_t
const)
const noexcept {
291 return caller_ !=
nullptr;
295 explicit operator bool () const noexcept {
return caller_ !=
nullptr; }
299 R operator () (A... args)
const {
301 return caller_(object_ptr_, std::forward<A>(args) ...);
308 using Caller = R (*)(
void*, A&& ...);
310 using Deleter = void (*)(
void*);
322 void* object_ptr_ =
nullptr;
326 std::shared_ptr<void> store_;
330 : caller_(m), object_ptr_(obj) { }
333 template <
typename T>
334 static void store_deleter(
void*
const ptr) {
335 using Rebind =
typename Allocator::template rebind<T>::other;
337 Rebind().destroy(
static_cast<T*
>(ptr));
338 Rebind().deallocate(
static_cast<T*
>(ptr), 1);
345 template <R(* Function)(A...)>
346 static R function_caller(
void*
const, A&& ... args) {
347 return Function(std::forward<A>(args) ...);
351 static R function_ptr_caller(
void*
const object_ptr, A&& ... args) {
352 return (*
reinterpret_cast<R(* const*)(A...)
>(&object_ptr))(args...);
356 template <
class C, R(C::* method_ptr)(A...)>
357 static R method_caller(
void*
const object_ptr, A&& ... args) {
358 return (
static_cast<C*
>(object_ptr)->*method_ptr)(
359 std::forward<A>(args) ...);
363 template <
class C, R(C::* method_ptr)(A...)
const>
364 static R const_method_caller(
void*
const object_ptr, A&& ... args) {
365 return (
static_cast<C const*
>(object_ptr)->*method_ptr)(
366 std::forward<A>(args) ...);
378 std::pair<C*
const, R(C::*
const)(A...)>;
384 std::pair<C
const*
const, R(C::*
const)(A...)
const>;
388 struct IsMemberPair : std::false_type { };
392 struct IsMemberPair<
MemberPair<C> >: std::true_type { };
396 struct IsConstMemberPair : std::false_type { };
403 template <
typename T>
404 static typename std::enable_if<
405 !(IsMemberPair<T>::value || IsConstMemberPair<T>::value), R
407 functor_caller(
void*
const object_ptr, A&& ... args) {
408 return (*
static_cast<T*
>(object_ptr))(std::forward<A>(args) ...);
412 template <
typename T>
413 static typename std::enable_if<
414 (IsMemberPair<T>::value || IsConstMemberPair<T>::value), R
416 functor_caller(
void*
const object_ptr, A&& ... args) {
417 return (
static_cast<T*
>(object_ptr)->first->*
418 static_cast<T*
>(object_ptr)->second)(std::forward<A>(args) ...);
425 template <
typename T,
typename Allocator = std::allocator<
void> >
426 using delegate = Delegate<T, Allocator>;
429 template <
class C,
typename R,
typename... A>
432 C*
const object_ptr, R(C::*
const method_ptr)(A...)) noexcept {
433 return Delegate<R(A...)>::template make<C>(object_ptr, method_ptr);
437 template <
class C,
typename R,
typename... A>
440 C*
const object_ptr, R(C::*
const method_ptr)(A...)
const) noexcept {
441 return Delegate<R(A...)>::template make<C>(object_ptr, method_ptr);
445 template <
class C,
typename R,
typename... A>
448 C& object_ptr, R(C::*
const method_ptr)(A...)) noexcept {
449 return Delegate<R(A...)>::template make<C>(object_ptr, method_ptr);
453 template <
class C,
typename R,
typename... A>
454 inline Delegate<R(A...)>
456 C
const& object_ptr, R(C::*
const method_ptr)(A...)
const) noexcept {
457 return Delegate<R(A...)>::template make<C>(object_ptr, method_ptr);
462 #endif // !TLX_DELEGATE_HEADER