简体   繁体   中英

How do you pass a reference when using a typename as a function argument in C++?

I have some weird problem with templates. When trying to pass a parameterised iterator it complains that no function can be found. The code snippet is here, forget about the functionality, it's using the reference to the templatized iterator what interests me

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

If you try to compile this with g++ v4.3.2 it complains with a message saying that:

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

Is there something wrong with the code I wrote or is that g++ needs more information?

g++ can't figure out which template overload of print_list_element it should use. If you explicitly specify the template parameter it works:

print_list_element<int>(it);

A better way is to write the function like this:

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

This will now work for any type of iterator, not just std::list<T>::iterator . Also, the template type will be deduced correctly from the argument.

I realize that it was a contrived example, but almost always you probably didnt want to pass in list<T>::iterator to a function anyways. At worst, at least template on ListType so that your code would work with lists with custom allocators.

这是非法的,因为std :: list <T> :: iterator不是标准所称的适当的推导上下文

The other responses are correct, but for completeness I'll just add that, by design, C++ can only deduce template arguments automatically in certain cases , and this isn't one of them.

When you think about it, you'll realise that automatic deduction in this case would lead to an undesirable situation. std::list<T>::iterator is not a real type, it's just a typedef alias for a real type (eg it might be T* ) to which it is immediately translated, so the compiler would have to build some sort of "reverse index" in order to map T* back to std::list<T>::iterator for automatic deduction of T to work here. But this mapping would break as soon as another class template was created that had a type member called iterator that was typedef ed to T* -- then the compiler would have two choices of what to translate T* to, and no way to choose between them. Clearly, any automatic deduction policy that breaks when an unrelated class adds a particular typedef type member is much too fragile to work.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM