This legendary C++ delegate article
http://www.codeproject.com/Articles/11015/The-Impossibly-Fast-C-Delegates
can be easily converted into C++11, without the need for fancy preprocessor magic in the original. I'd like to know if I got all the necessary C++11 nuances right. Suggestions?
#ifndef DELEGATE_HPP
# define DELEGATE_HPP
#include <utility>
template <typename T> class delegate;
template<class R, class ...A>
class delegate<R (A...)>
{
typedef R (*stub_ptr_type)(void*, A...);
delegate(void* o, stub_ptr_type m)
: object_ptr(o),
stub_ptr(m)
{
}
public:
delegate() : stub_ptr(0) { }
template <
typename T,
typename = typename std::enable_if<
!std::is_same<delegate, typename std::remove_reference<T>::type>::value
>::type
>
delegate(T&& f)
{
*this = from_functor(std::forward<T>(f));
}
delegate(delegate const&) = default;
delegate& operator=(delegate const&) = default;
template <R (*function_ptr)(A...)>
static delegate from_function()
{
return delegate(0, function_stub<function_ptr>);
}
template <class C, R (C::*method_ptr)(A...)>
static delegate from_method(C* object)
{
return delegate(object, method_stub<C, method_ptr>);
}
template <class C, R (C::*method_ptr)(A...)>
static delegate from_const_method(C const* object)
{
return delegate(const_cast<C*>(object), const_method_stub<C, method_ptr>);
}
template <typename T>
static delegate from_functor(T&& f)
{
static typename std::remove_reference<T>::type const l(
std::forward<T>(f));
return delegate(const_cast<void*>(static_cast<void const*>(&l)),
functor_stub<T>);
}
void reset()
{
stub_ptr = 0;
}
void swap(delegate& other)
{
std::swap(object_ptr, other.object_ptr);
std::swap(stub_ptr, other.stub_ptr);
}
bool operator==(delegate const& rhs) const
{
return (stub_ptr == rhs.stub_ptr)
&& (object_ptr == rhs.object_ptr);
}
bool operator<(delegate const& rhs) const
{
return (object_ptr < rhs.object_ptr)
|| (stub_ptr < rhs.stub_ptr);
}
explicit operator bool() const
{
return stub_ptr;
}
template <typename ...B>
R operator()(B&&... args) const
{
return (*stub_ptr)(object_ptr, std::forward<B>(args)...);
}
private:
void* object_ptr;
stub_ptr_type stub_ptr;
template <R (*function_ptr)(A...)>
static R function_stub(void*, A... args)
{
return (*function_ptr)(args...);
}
template <class C, R (C::*method_ptr)(A...)>
static R method_stub(void* object_ptr, A... args)
{
return (static_cast<C*>(object_ptr)->*method_ptr)(args...);
}
template <class C, R (C::*method_ptr)(A...) const>
static R const_method_stub(void* object_ptr, A... args)
{
return (static_cast<C const*>(object_ptr)->*method_ptr)(args...);
}
template <typename T>
static R functor_stub(void* object_ptr, A... args)
{
return (*static_cast<T*>(object_ptr))(args...);
}
};
#endif // DELEGATE_HPP
example use:
#include <iostream>
#include "delegate.hpp"
struct A
{
void foo(int a)
{
std::cout << "method got: " << a << std::endl;
}
};
void foo(int a)
{
std::cout << "function got: " << a << std::endl;
}
int main(int argc, char* argv[])
{
auto d1(delegate<void (int)>::from_function<foo>());
A a;
auto d2(delegate<void (int)>::from_method<A, &A::foo>(&a));
d1(1);
d2(2);
int b(2);
auto d3(delegate(
[b](){std::cout << "hello world: " << b << std::endl;}));
d3();
return 0;
}