如何仅传递mutex作为lock_guard构造函数参数且无需显式指定模板类型
当我像下面这样声明锁对象时:
lock_guard Locker(mLocker);
我希望编译器能够检测mLocker是否为mutex类型。
为实现这一需求,我使用concept requires定义了如下规则:
template <typename T> concept is_mutex = requires { std::is_same_v<T, std::recursive_mutex>; };
template <class T> requires is_mutex<T> using expLock = std::lock_guard<T>;
如上所示,我对类型T做了mutex类型校验,并通过using关键字为对应T类型的std::lock_guard定义了别名。
但当我使用该别名expLock声明锁对象时:
std::recursive_mutex mutex_Lock; expLock Locker(mutex_Lock); // 报错:别名模板expLock缺少参数列表
上述代码会触发编译错误。
我猜测是因为下面的代码将类型T强制绑定到std::lock_guard,导致std::lock_guard构造函数的explicit关键字被忽略了:
template <class T> requires is_mutex<T> using expLock = std::lock_guard<T>;
// 类模板 lock_guard template <class _Mutex> class _NODISCARD lock_guard { // 析构时自动解锁mutex的类 public: using mutex_type = _Mutex; explicit lock_guard(_Mutex& _Mtx) : _MyMutex(_Mtx) { // 构造并加锁 _MyMutex.lock(); } ... private: _Mutex& _MyMutex; };
当然,如果像下面这样为别名expLock指定类型T,就不会出现编译错误:
std::recursive_mutex mutex_Lock; expLock<std::recursive_mutex> Locker(mutex_Lock);
但我希望下面的代码可以无编译错误运行:
template <typename T> concept is_mutex = requires { std::is_same_v<T, std::recursive_mutex>; };
template <class T> requires is_mutex<T> using expLock = std::lock_guard<T>;
std::recursive_mutex mutex_Lock; expLock Locker(mutex_Lock); // 报错:别名模板expLock缺少参数列表
如何仅传递mutex作为lock_guard构造函数参数?
我是应该自定义一个类似std::lock_guard的新锁类,还是修改现有别名定义?或者有其他新的解决方案?
问题解答
根据cppreference的说明,MSVC从19.27版本开始实现了P1814提案,因此如果你的MSVC版本高于19.27,开启/std:c++latest编译标志后代码即可正常编译。—— 康桓瑋
如果当前项目使用的MSVC版本为19.27及以上,可以省略using关键字对应的模板参数列表。但如果你使用Visual Studio的Intellisense,可能仍会显示错误提示。如果MSVC 19.27及以上版本弹出using关键字的模板参数列表错误,该错误大概率是Intellisense补丁未适配MSVC版本导致的,除了Intellisense的错误提示外,实际构建可以正常运行。—— 정명준
内容的提问来源于stack exchange,提问作者정명준

