Last active
March 7, 2019 09:46
-
-
Save r3mus-n0x/2f983d3384c23b8be9b3d5e1ad923ae2 to your computer and use it in GitHub Desktop.
The essence of std::function and type-erase in general
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <type_traits> | |
#include <utility> | |
template <typename F> | |
class Function; | |
template <typename Ret, typename... Args> | |
class Function<Ret(Args...)> | |
{ | |
public: | |
Function() | |
: _functor(nullptr) | |
{ } | |
template <typename F, | |
std::enable_if_t<!std::is_same_v<F, Function>, bool> = true, | |
std::enable_if_t<std::is_invocable_v<F, Args...>, bool> = true, | |
std::enable_if_t<std::is_same_v<Ret, void> || std::is_convertible_v<std::invoke_result_t<F, Args...>, Ret>, bool> = true> | |
Function(F functor) | |
: _functor(new Functor<F>(std::move(functor))) | |
{ } | |
Function(const Function &that) | |
: _functor(that._functor ? that._functor->clone() : nullptr) | |
{ } | |
Function(Function &&that) | |
: Function() | |
{ | |
std::swap(_functor, that._functor); | |
} | |
~Function() | |
{ | |
delete _functor; | |
} | |
Function & operator=(Function that) | |
{ | |
std::swap(_functor, that._functor); | |
return *this; | |
} | |
explicit operator bool() const | |
{ | |
return _functor != nullptr; | |
} | |
Ret operator()(Args... args) const | |
{ | |
return (*_functor)(args...); | |
} | |
private: | |
class IFunctor | |
{ | |
public: | |
virtual ~IFunctor() = default; | |
virtual IFunctor * clone() const = 0; | |
virtual Ret operator()(Args... args) = 0; | |
}; | |
template <typename F> | |
class Functor : public IFunctor | |
{ | |
public: | |
Functor(F functor) | |
: _functor(std::move(functor)) | |
{ } | |
IFunctor * clone() const override | |
{ | |
return new Functor<F>(_functor); | |
} | |
Ret operator()(Args... args) override | |
{ | |
if constexpr (!std::is_same_v<Ret, void>) | |
return _functor(args...); | |
else | |
static_cast<void>(_functor(args...)); | |
} | |
private: | |
F _functor; | |
}; | |
IFunctor *_functor; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment