#include <iostream>
#include <type_traits>
#include <memory>
#include <string>
#include <vector>

using namespace std;

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>
auto make_move_on_copy(T&& aValue) -> typename enable_if<is_rvalue_reference<decltype(aValue)>::value, move_on_copy<T>>::type
{
	return move_on_copy<T>(move(aValue));
}

template<typename F>
void invoke(F f)
{
    f();
}

// some trials
int main() 
{
   	unique_ptr<int> aPtr(new int(5));
	auto aPtrMov = make_move_on_copy(move(aPtr));
	unique_ptr<int> aPtr2(new int(5));
	auto aPtrMov2 = make_move_on_copy(move(aPtr2));

	auto aPtrLam = [aPtrMov] 
	{
		cout << "Ptr value: " << *(aPtrMov.Value()) << endl;
	};

	auto aPtrMutableLam = [aPtrMov2] () mutable
	{
		(*aPtrMov2.Value())++;
		cout << "Ptr value: " << *(aPtrMov2.Value()) << endl;
	};   

	invoke(aPtrLam);
	invoke(aPtrMutableLam);
	invoke(aPtrMutableLam);


   return 0;
}