Как передать ссылку при использовании typename в качестве аргумента функции в C ++? - PullRequest
3 голосов
/ 15 апреля 2009

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

#include <list>
#include <iostream>

template<typename T>
void print_list_element(typename std::list<T>::iterator& it){
    std::cout << *it << std::endl;
}

int main() {
    std::list<int> theList;
    theList.push_back(1);

    std::list<int>::iterator it = theList.begin();
    print_list_element(it);

    return 0;
}

Если вы попытаетесь скомпилировать это с помощью g ++ v4.3.2, вы получите сообщение о том, что:

main.cpp:14: error: no matching function for call to 'print_list_element(std::_List_iterator<int>&)'

Что-то не так с кодом, который я написал, или g ++ нуждается в дополнительной информации?

Ответы [ 4 ]

9 голосов
/ 15 апреля 2009

g ++ не может определить, какую перегрузку шаблона print_list_element он должен использовать. Если вы явно указываете параметр шаблона, он работает:

print_list_element<int>(it);
5 голосов
/ 15 апреля 2009

Лучше написать такую ​​функцию:

template<typename Iter>
void print_element(Iter it){
    std::cout << *it << std::endl;
}

Теперь это будет работать для любого типа итератора, а не только для std::list<T>::iterator. Кроме того, тип шаблона будет правильно выведен из аргумента.

Я понимаю, что это был надуманный пример, но почти всегда вы, вероятно, не хотели передавать list<T>::iterator функции в любом случае. В худшем случае, по крайней мере, шаблон для ListType, чтобы ваш код работал со списками с пользовательскими распределителями.

4 голосов
/ 15 апреля 2009

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

Когда вы подумаете об этом, вы поймете, что автоматическое удержание в этом случае приведет к нежелательной ситуации. std::list<T>::iterator не является реальным типом, это просто псевдоним typedef для реального типа (например, это может быть T*), на который он немедленно преобразуется, поэтому компилятору придется создавать некий «обратный индекс» чтобы отобразить T* обратно на std::list<T>::iterator для автоматического удержания T, чтобы работать здесь. Но это отображение прервется, как только будет создан другой шаблон класса, который имеет элемент типа с именем iterator, который был typedef преобразован в T* - тогда у компилятора будет два варианта, на что переводить T*, и нет возможности выбирать между ними. Ясно, что любая политика автоматического вывода, которая нарушается, когда несвязанный класс добавляет конкретный член typedef типа , слишком хрупок, чтобы работать.

4 голосов
/ 15 апреля 2009

Это недопустимо, потому что std :: list :: iterator - это не то, что стандарт называет правильным выводимым контекстом

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...