Почему этот вывод шаблона не работает

Этот код не будет компилироваться с clang++ 6.0 или g++ 4.9.1 (код не имеет значения, но это минимальный пример, который позволяет это сделать):

#include <forward_list>

template<typename T>
T getItem(typename std::forward_list<T>::const_iterator it) {
    return *it;
}

template<typename T>
void foo() {
    std::forward_list<T> list;
    auto item = getItem(list.cbegin());
}

template<typename T>
void bar(const std::forward_list<T>& list) {
    auto item = getItem(list.cbegin());
}

int main() {
    std::forward_list<int> list;
    bar(list);
}

я получаю эту ошибку

t2.cpp:17:17: error: no matching function for call to 'getItem'
    auto item = getItem(list.cbegin());
                ^~~~~~~
t2.cpp:22:5: note: in instantiation of function template specialization 'bar<int>' requested here
    bar(list);
    ^
t2.cpp:4:3: note: candidate template ignored: couldn't infer template argument 'T'
T getItem(typename std::forward_list<T>::const_iterator it) {
  ^
1 error generated.

Чтобы исправить это, мне нужно изменить вызов bar() следующим образом:

template<typename T>
void bar(const std::forward_list<T>& list) {
    auto item = getItem<T>(list.cbegin());
}

Я не понимаю, почему компилятор не может вывести аргумент шаблона, и странно то, что компилятор вполне доволен foo().


person garph0    schedule 10.11.2014    source источник
comment
Вы можете сами вывести параметр: template<typename T> auto getItem(T it) -> decltype(*it) { return *it; }. Не очень хорошая идея, но работает ))   -  person borisbn    schedule 10.11.2014
comment
Что не так с auto item = *list.begin();?   -  person Casey    schedule 10.11.2014


Ответы (1)


Вы пытаетесь вывести аргумент шаблона из невыведенного контекста, § [temp.deduct.type]/5

Невыведенные контексты:

— Спецификатор вложенного имени типа, который был указан с помощью квалифицированного идентификатора.

i.e.

template<typename T>
T getItem(typename std::forward_list<T>::const_iterator it)
                   ^^^^^^^^^^^^^^^^^^^^

и § [temp.deduct.type]/4

Однако в некоторых контекстах значение не участвует в выводе типа, а вместо этого использует значения аргументов шаблона, которые были либо выведены в другом месте, либо явно указаны. Если параметр шаблона используется только в невыведенных контекстах и ​​не указан явно, вывод аргумента шаблона завершается ошибкой.

Если вы попытаетесь создать экземпляр foo , вы получите ту же ошибку. Вы не получаете ошибок для foo с приведенным выше кодом, так как зависимые имена просматриваются только при создании экземпляра (это обычно называется двухэтапным поиском). Ср. Семантическая корректность неэкземплярных шаблонных функций C++

person Marco A.    schedule 10.11.2014