Skip to content

Instantly share code, notes, and snippets.

@r3mus-n0x
Last active March 7, 2019 09:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save r3mus-n0x/2f983d3384c23b8be9b3d5e1ad923ae2 to your computer and use it in GitHub Desktop.
Save r3mus-n0x/2f983d3384c23b8be9b3d5e1ad923ae2 to your computer and use it in GitHub Desktop.
The essence of std::function and type-erase in general
#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