c++templatesaliasfunction-pointersmake-shared

How can I alias std::make_shared?


I have a template wrapper ThreadSafeVar for convenient mutex-locking of variables, and I want to alias std::shared_ptr and std::make_shared so I can do e.g. ThreadSafePtr<int> a = ThreadSafePtr_make<int>(2), but I can't figure out how to make ThreadSafePtr_make take arguments.

#include <memory>
#include <mutex>

template<typename T>
class ThreadSafeVar
{
    T value;
    std::mutex mutex{};

public:
    template<typename... Args>
    ThreadSafeVar(Args&&... args) : value{ std::forward<Args>(args)... } {}
    ThreadSafeVar(ThreadSafeVar&) = delete;
    ThreadSafeVar(ThreadSafeVar&&) = delete;
    ThreadSafeVar& operator=(ThreadSafeVar&) = delete;
    ThreadSafeVar& operator=(ThreadSafeVar&&) = delete;

    class Lock
    {
        friend class ThreadSafeVar<T>;
        T& ref;
        std::unique_lock<std::mutex> lock;
        Lock(ThreadSafeVar* tsvar) : ref{ tsvar->value }, lock{ tsvar->mutex } {}
    public:
        T & get() const { return ref; }
    };

    Lock lock() { return Lock{ this }; }
};

template<typename T>
using ThreadSafePtr = std::shared_ptr<ThreadSafeVar<T>>;

template<typename T>
constexpr auto ThreadSafePtr_make = std::make_shared<ThreadSafeVar<T>>;

template <typename T, typename... Args>
constexpr ThreadSafePtr<T>(*ThreadSafePtr_make2)(Args&&...) = &std::make_shared<ThreadSafeVar<T>>;

int main()
{
    ThreadSafePtr<int> a = std::make_shared<ThreadSafeVar<int>>(2);
    a->lock().get()++;
    ThreadSafePtr<int> b = ThreadSafePtr_make<int>();
    ThreadSafePtr<int> c = ThreadSafePtr_make<int>(2); // fail, too many arguments
    ThreadSafePtr<int> d = ThreadSafePtr_make2<int>(2); // fail, too many arguments

    return 0;
}

How do I alias std::make_shared so that it takes arguments?


Solution

  • Don't use a function pointer. Use a wrapper function template instead:

    template <typename T, typename... Args>
    ThreadSafePtr<T> ThreadSafePtr_make(Args&&... args)
    {
        return std::make_shared<ThreadSafeVar<T>>(std::forward<Args>(args)...);
    }