#include <iostream>
#include <mutex>
#include <thread>

template <typename MUTEX, typename RESOURCE> class LockedResource
{
    using my_type     = LockedResource<MUTEX, RESOURCE>;
    using mutex_t     = MUTEX;
	using type_t      = RESOURCE;
    using thread_id_t = std::thread::id;

    mutex_t     m_mutex;
    type_t      m_resource;
    thread_id_t m_thread_id{};

public:
	template <typename ... ARGS>
	LockedResource(ARGS &&... args) :
		m_resource(std::forward<ARGS>(args) ...)
	{}

    class Handler
    {
        using lock_t = std::unique_lock<mutex_t>;

        lock_t      m_lock;
        type_t      &m_resource;
        thread_id_t &m_thread_id;

        friend class LockedResource;

        Handler(mutex_t &a_mutex, type_t &a_resource, thread_id_t a_thread_id) :
            m_lock{a_mutex},
            m_resource{a_resource},
            m_thread_id{a_thread_id}
        {}
    public:
        Handler(Handler &&a_handler) :
            m_lock{std::move(a_handler.m_lock)},
            m_resource{a_handler.m_resource},
            m_thread_id{a_handler.m_thread_id}
        {}

        ~Handler()
        {
            m_thread_id = {};
        }
        type_t *operator->() const
        {
            return &m_resource;
        }

        friend std::ostream &operator<<(std::ostream &o, const Handler &h) { return o << h.m_resource; }
    };

    Handler get() throw(std::runtime_error)
	{
        if (m_thread_id == std::this_thread::get_id())
        {
            using namespace std::string_literals;
            throw std::runtime_error{"Double lock at "s.append(__PRETTY_FUNCTION__)};
        }

        return {m_mutex, m_resource, m_thread_id = std::this_thread::get_id()};
    }

    friend std::ostream &operator<<(std::ostream &o, my_type &lr) { return o << lr.get(); }
};

template <typename T> using Resource = LockedResource<std::mutex, T>;

#include <vector>
#include <string>

Resource<std::vector<int>> locked_vector{10, 10};
Resource<std::string> locked_string{"Hello world!"};

int main()
{
	const auto &vec = locked_vector.get();
	std::cout << vec->size() << '\n';
    //locked_vector.get();

    std::cout << locked_string << '\n';

    return 0;
}