#include <functional>
template<typename Ret, typename ...Args>
class stack_function_base {
typedef stack_function_base<Ret, Args...> self_type;
public:
virtual Ret do_call(Args&& ...) = 0;
virtual ~stack_function_base() {}
virtual self_type* copy_to(void*) = 0;
virtual self_type* move_to(void*) = 0;
};
template<typename F, typename Ret, typename ...Args>
class stack_function_impl : public stack_function_base<Ret, Args...>
{
typedef stack_function_base<Ret, Args...> base;
public:
stack_function_impl(F&& fn)
: fn_(std::forward<F>(fn))
{}
Ret do_call(Args&& ... args) override final {
return fn_(std::forward<Args>(args)...);
}
base* copy_to(void* addr) override final {
return new (addr) stack_function_impl(*this);
}
base* move_to(void* addr) override final {
return new (addr) stack_function_impl(std::move(*this));
}
private:
F fn_;
};
template<size_t MaxSize, typename Ret, typename ...Args>
class stack_function
{
typedef stack_function_base<Ret, Args...> fn_interface;
public:
stack_function() : fn_(nullptr) {}
stack_function(const stack_function& rhs) : fn_(0) {
if(rhs.fn_)
fn_ = rhs.fn_->copy_to(fn_storage_.data_);
}
stack_function( stack_function& rhs) : fn_(0) {
if(rhs.fn_)
fn_ = rhs.fn_->copy_to(fn_storage_.data_);
}
stack_function& operator =(const stack_function& rhs) {
if(fn_) destroy_();
if(rhs.fn_) fn_ = rhs.fn_->copy_to(fn_storage_.data_);
}
stack_function& operator =(stack_function& rhs) {
if(fn_) destroy_();
if(rhs.fn_) fn_ = rhs.fn_->copy_to(fn_storage_.data_);
}
stack_function(stack_function&& rhs) : fn_(nullptr) {
if(rhs.fn_) fn_ = rhs.fn_->move_to(fn_storage_.data_);
}
stack_function& operator=(stack_function&& rhs) {
if(fn_) destroy_();
if(rhs.fn_) fn_ = rhs.fn_->move_to(fn_storage_.data_);
}
template<typename F>
stack_function(F&& f) : fn_(0) {
construct_(std::forward<F>(f));
}
template<typename F>
void assign(F&& f) {
if(fn_) destroy_();
construct_(std::forward<F>(f));
}
~stack_function() {
if(fn_) destroy_();
}
operator bool() const {
return fn_ != nullptr;
}
Ret operator()(Args&& ... args) {
if(!fn_)
throw std::bad_function_call();
return fn_->do_call(std::forward<Args>(args)...);
}
private:
void destroy_() {
fn_->~fn_interface();
fn_ = 0;
}
template<typename F>
void construct_(F&& f) {
typedef stack_function_impl<F, Ret, Args...> fn_type;
static_assert(sizeof(fn_type) <= MaxSize
, "non sufficient stack_function storage size");
fn_ = new (fn_storage_.data_) fn_type(std::forward<F>(f));
}
private:
fn_interface* fn_;
union {
long double align_;
unsigned char data_[MaxSize];
} fn_storage_;
};
#include <iostream>
struct foo {
foo() { std::cout << "foo constructor" << std::endl; }
foo(const foo&) { std::cout << "foo copy constructor" << std::endl; }
foo(foo&&) { std::cout << "foo move constructor" << std::endl; }
void operator()() { std::cout << "foo call" << std::endl; }
};
int main()
{
typedef stack_function<8, void> callback;
callback c1 = foo();
c1();
callback c2 = std::move(c1);
c2();
callback c3 = c2;
c3();
return 0;
}