Home > Software design >  How to pass only mutex to lock_guard constructor parameter
How to pass only mutex to lock_guard constructor parameter

Time:11-15

When declare locker like,

lock_guard Locker(mLocker);


I want the compiler to detect if an mLocker is a mutex.

To implement this, I used concept requires and defined as below.

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>;


As above, the mutex was verified for type T, and std::lock_guard for type T was aliased through using keyword.

But when declaring a locker with that alias(expLock).

std::recursive_mutex mutex_Lock;
expLock Locker(mutex_Lock); // error : No argument list for alias template expLock.


Above code causes a compile error.

It seems that the explicit keyword of the std::lock_guard constructor was ignored because the code below forced type T to std::lock_guard.

template <class T> requires is_mutex<T> using expLock = std::lock_guard<T>;
// CLASS TEMPLATE lock_guard
template <class _Mutex>
class _NODISCARD lock_guard { // class with destructor that unlocks a mutex
public:
    using mutex_type = _Mutex;

    explicit lock_guard(_Mutex& _Mtx) : _MyMutex(_Mtx) { // construct and lock
        _MyMutex.lock();
    }

    ...

private:
    _Mutex& _MyMutex;
};


Of course, if type T is specified in the alias(expLock) as shown below, no compilation error occurs.

std::recursive_mutex mutex_Lock;
expLock<std::recursive_mutex> Locker(mutex_Lock);


But I want the code below to work without compile errors.

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); // error : No argument list for alias template expLock.


How to pass only mutex to lock_guard constructor parameter?

Should I define a new Locker class like std::lock_guard? or Do I need to fix the alias?

Is that too or is there a new solution?



This question has been answered in the comments below.

According to cppreference, MSVC implemented P1814 after 19.27*, so if your MSVC version is newer than 19.27*, your code will compile when use the /std:c latest flag. – 康桓瑋

If the MSVC of the current project is version 19.27 or later, you can omit the template argument list for the using keyword. However, if you are using Visual Studio's Intellisense, Intellisense may display an error message. If a template argument list error message for the using keyword is popped up in MSVC 19.27 or later, This error message may be caused by the Intellisense patch not based on the MSVC version. Apart from the error message that Intellisense pops up, the build works without any problem. - 정명준

CodePudding user response:

First, Your concept of is_mutex is incorrectly defined. It will only check the validity of is_same_v in the requires clause without evaluating it. You need to define it as:

template <typename T>
concept is_mutex = requires { requires std::is_same_v<T, std::recursive_mutex>; };

Or just:

template <typename T>
concept is_mutex = std::is_same_v<T, std::recursive_mutex>;

Above code causes a compile error.

In fact, the above code is well-formed in C 20. I guess you are using Clang, which currently does not implement Class Template Argument Deduction for Alias Templates.

  • Related