Reputation: 3142
Why in the following piece of code, does the template type cannot be deduced automatically from the last argument, like it does in std::condition_variable::wait
?
template< typename Predicate >
//requires Truth< Predicate >
class lock_monitor_guard
{
public:
lock_monitor_guard( std::mutex& mutex, std::condition_variable& monitor, Predicate predicate );
~lock_monitor_guard();
private:
std::unique_lock<std::mutex> lock;
std::condition_variable& monitor;
};
template< typename Predicate >
//requires Truth< Predicate >
lock_monitor_guard<Predicate>::lock_monitor_guard( std::mutex& mutex, std::condition_variable& monitor, Predicate predicate )
: lock( mutex ), monitor( monitor )
{
monitor.wait<Predicate>( lock, predicate );
}
template< typename Predicate >
//requires Truth< Predicate >
lock_monitor_guard<Predicate>::~lock_monitor_guard()
{
lock.unlock();
monitor.notify_one();
}
When I try to build a line like lock_monitor_guard guard( jobs_mutex, jobs_monitor, ([]()->bool{return true;}) );
, I have an error message : use of class template 'lock_monitor_guard' requires template arguments
. But why ? And why does it work with the STL std::condition_variable::wait
. Thank you for any help !
Upvotes: 1
Views: 392
Reputation: 168998
Template arguments for types cannot be deduced, period. This is because type specializations can provide a completely different set of members, so until you know the type's template arguments you don't even know what constructors are available.
This is why the standard library has helper functions, like std::make_pair
. When constructing or referring to an std::pair
you must specify the type arguments (std::pair<int, double>(1, 2.0)
) but in most cases they can be deduced when calling a function (std::make_pair(1, 2.0)
). (Note that std::condition_variable::wait
is a function, not a type.)
If you implement a move constructor for your lock_monitor_guard
type then you can create a helper function similar in spirit to std::make_pair
and then use copy-initialization with auto
to provide deduction. (Note that you'll also have to tweak your destructor to account for the possibility that this
had its contents "stolen" by the move constructor.)
template <typename Predicate>
lock_monitor_guard<Predicate> create_lock_monitor_guard(
std::mutex & mutex,
std::condition_variable & monitor,
Predicate && predicate)
{
return lock_monitor_guard<Predicate>(mutex, monitor, std::forward<Predicate>(predicate));
}
auto guard = create_lock_monitor_guard(
jobs_mutex,
jobs_monitor,
[] { return true; });
Upvotes: 6
Reputation: 4025
You can pass the type as shown below.
template< typename Predicate >
//requires Truth< Predicate >
class lock_monitor_guard
{
public:
lock_monitor_guard( std::mutex& mutex, std::condition_variable& monitor, Predicate predicate );
};
auto pred = [] { return true; };
lock_monitor_guard<decltype(pred)> l(jobs_mutex, jobs_monitor, pred);
And std::condition_variable::wait
is function and not type hence the type is automatically deduced.
Upvotes: 2