2014-12-30 2 views
1

Почему в следующем фрагменте кода тип шаблона не может быть выведен автоматически из последнего аргумента, как в 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(); 
} 

Когда я пытаюсь построить линию как lock_monitor_guard guard(jobs_mutex, jobs_monitor, ([]()->bool{return true;}));, у меня есть сообщение об ошибке: use of class template 'lock_monitor_guard' requires template arguments. Но почему ? И почему он работает с STL std::condition_variable::wait. Спасибо за любую помощь !

+1

Вы должны указать тип шаблона lock_monitor_guard. – Jagannath

+0

Да, но почему? Я не хочу угадывать ужасный тип лямбды! И почему 'std :: condition_variable :: wait' отличается? –

+5

вы можете перемещать 'template ', чтобы сделать его частью объявления конструктора, тогда он будет работать. весь класс 'lock_monitor_guard' не должен быть параметризован с типом' Predicate' –

ответ

6

Шаблонные аргументы для типов не могут быть выведены, период. Это связано с тем, что специализация типов может предоставить совершенно другой набор членов, поэтому пока вы не узнаете аргументы шаблона типа, вы даже не знаете, какие конструкторы доступны.

Именно поэтому стандартная библиотека имеет вспомогательные функции, такие как std::make_pair. При построении или обращении к std::pair вы должны указать аргументы типа (std::pair<int, double>(1, 2.0)), но в большинстве случаев их можно вывести при вызове функции (std::make_pair(1, 2.0)). (Обратите внимание, что std::condition_variable::wait является функцией, а не тип.)

Если реализовать конструктор перемещения для lock_monitor_guard типа, то вы можете создать вспомогательную функцию, аналогичную по духу std::make_pair, а затем использовать копию инициализацию с auto, чтобы обеспечить вывод , (Обратите внимание, что вы также должны настроить свой деструктор, чтобы учесть возможность того, что this было его содержание «похищенное» конструктор перемещения.)

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; }); 
+0

Не мог ли компилятор выбрать среди всех конструкторов всей возможной специализации, когда тип оставлен для вычета? –

+0

@ Lærne Может ли язык быть изменен, чтобы это можно было сделать? Возможно. Но стандарт не позволяет этого, поэтому этого не происходит. Кроме того, вы сталкиваетесь с ситуацией, когда кто-то вводит новую специализацию, а ваш код нарушает или ведет себя по-другому, потому что внезапный вывод является либо двусмысленным, либо приводит к выбору другого типа, чем вы предполагали. Как и сегодня, этот тип должен быть известен до того, как будут проверены конструкторы. Чтобы вывести, вы должны были бы вывести уже! Курица и яйцо. – cdhowie

+0

@ Lærne Конечно. Если вы знаете, как написать компилятор, способный оценивать бесконечное количество возможных экземпляров за конечное время и память. –

2

Вы можете передать тип, как показано ниже.

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

И std::condition_variable::wait это функция, а не тип, следовательно, тип автоматически выводится.

Смежные вопросы