Function

One of my favourate additions to C++11 was std::function because it provides a very elegant solution on how to run something either at a later point in time or on a different context (like a thread).

In C++03 you would have to use something like this.

class Fn
{
protected:
    virtual ~Fn() {}
    virtual exec() = 0;
};

You would then create a derives class of Fn on the heap and pass the pointer to the context you want to execute. Finally you would delete your pointer to Fn

C++11 makes things much easier. All you do is pass a std::function. A std::function can be initialized using std::bind or better, using a lamda with capture. Any data remains captured until required.

std::function does have a downside, I cannot capture a std::unique_ptr. This is cause std::function is copyable and std::unique_ptr is not.

This can be solved using our own Function object looking something like:


#include <utility>
#include <type_traits>

template <typename R, typename... Args>
class CallBase 
{
public:
	virtual ~CallBase() {}
	virtual R call(Args... args) = 0;
};

template <typename F, typename R, typename... Args>
class Call : public CallBase<R,Args...>
{
public:
	Call(F f)
		: m_f{ std::forward<F>(f) }
	{}
	R call(Args ...args) override {
		return m_f(std::forward<Args>(args)...);
	}

private:
	F m_f;
};

template <typename Sig>
class Function;

template <typename R, typename... Args>
class Function<R(Args...)>
{
public:
	Function()
		: m_call(nullptr)
	{}
	
	Function(std::nullptr_t)
		: m_call(nullptr)
	{}

	template <typename F>
	Function (F f)
		: m_call (new Call<F, R, Args...>(std::forward<F>(f)))
	{
		static_assert(
			std::is_same< typename
				std::invoke_result<F,Args...>::type, R 
			>::value, "Return type must match function");
	}

	Function(Function&& rhs) noexcept 
		: m_call{ rhs.m_call }
	{
		rhs.m_call = nullptr;		
	}

	void swap(Function& rhs) noexcept{
		std::swap(this->m_call, rhs.m_call);
	}

	Function& operator=(const Function&) = delete;

	Function& operator=(Function&& rhs) noexcept
	{
		m_call = rhs.m_call;
		rhs.m_call = nullptr;
	}

	~Function()
	{
		delete m_call;
	}

	operator bool() const noexcept 
	{
		return m_call != nullptr;
	}

	R operator()(Args ... args)
	{
		return m_call->call(std::forward<Args>(args)...);
	}

	bool operator==(const Function& rhs) const noexcept
	{
		return m_call == rhs.m_call;
	}

private:
	CallBase<R, Args...>* m_call;
};

There is nothing like the std::bind interface but that is ok since you can get everything you need from lambdas as illustated. Just note that move captures only works from c++14.