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?
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)...);
}