#include <functional>
#include <iostream>
#include <vector>

//////////////////////////////////////////////////////////////////////////////// MOVE_ON_COPY

template<typename T>
struct move_on_copy 
{
    move_on_copy(T&& aValue) : value(move(aValue)) {}
	move_on_copy(const move_on_copy& other) : value(move(other.value)) {}
	
	T& Value() 
	{
		return value;
	}
	
	const T& Value() const
	{
		return value;
	}
	
private:
	mutable T value;
	move_on_copy& operator=(move_on_copy&& aValue);
	move_on_copy& operator=(const move_on_copy& aValue);
};


template <typename T>
move_on_copy<typename std::remove_reference<T>::type> make_move_on_copy_wrapper_internal(typename std::remove_reference<T>::type&& aValue) 
{
	return move_on_copy<typename std::remove_reference<T>::type>(std::move(aValue));
}

template <typename T>
move_on_copy<T> make_move_on_copy_wrapper(T&& aValue) 
{
	return make_move_on_copy_wrapper_internal<T>(std::forward<T>(aValue));
}

//////////////////////////////////////////////////////////////////////////////// MOVE_ON_COPY

template<typename T>
struct mfunction;

template<class ReturnType, typename... ParamType>
struct mfunction<ReturnType(ParamType...)> : public std::function<ReturnType(ParamType...)>
{
    typedef std::function<ReturnType(ParamType...)> FnType;

    mfunction() : FnType() 
	{}

	template<typename T>
    explicit mfunction(T&& fn) : FnType(std::forward<T>(fn))
	{}
    	
	mfunction(mfunction&& other) : FnType(move(static_cast<FnType&&>(other)))
	{}
    
    mfunction& operator=(mfunction&& other)
	{
     FnType::operator=(move(static_cast<FnType&&>(other))); 
     return *this;
	}
	
	mfunction(const mfunction&) = delete;
	mfunction& operator=(const mfunction&)  = delete;
};

// examples

using namespace std;

struct ToCapture
{
    ToCapture() {}
    ToCapture(ToCapture const&) { cout << "copied!" << endl; }
    ToCapture(ToCapture&&) { cout << "moved!" << endl; }
};

void myFunction()
{
    cout << "myFunction" << endl;
}


mfunction<void()> Create()
{
	vector<int> vec {1,2,3};
	auto wrap = make_move_on_copy_wrapper(move(vec));
	mfunction<void()> f([wrap](){ cout << wrap.Value().size() << endl;	 });
	return f;
}

int use_m_function_as_std_function(function<int(int, int)>& f)
{
    return f(10,20);
}

int main()
{
//1) creation
    	ToCapture toCapt;
		// from lambda
		mfunction<void(int, string)> mfunction_1 ( [toCapt] (int i, string s) { cout << s << " " << i << endl;} );
		mfunction_1(1, "Hello");
		// from function pointer
		mfunction<void()> m_function_2 (&myFunction);
		m_function_2();
		// from std::function
		std::function<void(int)> stdFunc1 ([toCapt](int) {});
		cout << "---stdFunc1 created---" << endl;
		mfunction<void(int)> m_function3 (stdFunc1);
		stdFunc1(1);		
		m_function3(1);
		
	//2) noncopyability
		// auto mfunction_2 = mfunction_1;
		auto mfunction_2 = move(mfunction_1);
		//mfunction_2 = [](int,string){};
		//m_function_2 = mfunction_1;
		
	//3) using
		auto mfunction_3 = Create();
		mfunction_3();    
        mfunction<int(int,int)> mfunction_4([](int a, int b){ return a+b; });
        cout << use_m_function_as_std_function(mfunction_4) << endl;
        
        return 0;
}