如何为std::make_shared创建支持传参的别名?
现有一个线程安全变量包装类ThreadSafeVar,希望为std::shared_ptr<ThreadSafeVar<T>>创建别名ThreadSafePtr<T>,同时为std::make_shared<ThreadSafeVar<T>>创建可接收参数的别名,实现类似ThreadSafePtr<int> a = ThreadSafePtr_make<int>(2)的调用,但原代码中的两种别名方式均无法支持参数传递。
原代码问题点:
ThreadSafePtr_make将std::make_shared<ThreadSafeVar<T>>赋值给变量,实际绑定的是无参版本的函数指针,传递参数会因签名不匹配报错。ThreadSafePtr_make2尝试用模板函数指针,但调用时无法推导Args模板参数,导致编译失败。
直接定义一个模板函数,内部调用std::make_shared<ThreadSafeVar<T>>并完美转发参数,这是最简洁且兼容所有参数场景的方案。
修改后的完整代码
#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>>; // 核心:用模板函数包装std::make_shared,完美转发参数 template <typename T, typename... Args> constexpr ThreadSafePtr<T> ThreadSafePtr_make(Args&&... args) { return std::make_shared<ThreadSafeVar<T>>(std::forward<Args>(args)...); } 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); // 支持多参数构造(比如T是std::pair的情况) ThreadSafePtr<std::pair<int, std::string>> d = ThreadSafePtr_make<std::pair<int, std::string>>(10, "test"); return 0; }
方案说明
- 完美转发:通过
std::forward<Args>(args)...保证参数的左值/右值属性不变,和直接调用std::make_shared的效率一致。 - 兼容所有参数场景:支持
ThreadSafeVar<T>构造函数的任意参数组合,包括无参、单参、多参、甚至带默认值的参数。 - 编译期优化:
constexpr修饰保证在编译期即可完成实例化(符合C++17及以上标准)。
内容的提问来源于stack exchange,提问作者H.v.M.
相关产品推荐
相关产品推荐

