#pragma once #include #include namespace hr { template class function; /* callable objects derived from funbase can be retrieved from hr::function using target_base */ struct funbase { virtual ~funbase() {} }; template struct function_state_base { virtual R call(Args...) const = 0; virtual function_state_base *clone() const = 0; virtual ~function_state_base() {} virtual funbase* as_funbase() = 0; }; template struct function_state : function_state_base { T t_; explicit function_state(T t) : t_(std::move(t)) {} R call(Args... args) const override { return const_cast(t_)(static_cast(args)...); } function_state_base *clone() const override { return new function_state(*this); } funbase* as_funbase() override { if(std::is_base_of::value) return (funbase*) (&t_); return nullptr; } }; template class function { function_state_base *ptr_; public: function() : ptr_(nullptr) {} template::type>()(std::declval()...)))> function(Callable&& t) : ptr_(new function_state::type, R, Args...>(static_cast(t))) {} ~function() { delete ptr_; } function(function& rhs) : ptr_(rhs.ptr_ ? rhs.ptr_->clone() : nullptr) {} function(const function& rhs) : ptr_(rhs.ptr_ ? rhs.ptr_->clone() : nullptr) {} function(function&& rhs) noexcept : ptr_(rhs.ptr_) { rhs.ptr_ = nullptr; } function(const function&& rhs) = delete; void operator=(function rhs) noexcept { std::swap(ptr_, rhs.ptr_); } R operator()(Args... args) const { return ptr_->call(static_cast(args)...); } explicit operator bool() const noexcept { return ptr_ != nullptr; } template T* target() { auto ptr = dynamic_cast*> (ptr_); if(!ptr) return nullptr; return &ptr->t_; } struct funbase* target_base() { return ptr_->as_funbase(); } }; } // namespace hr