Hi,
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);
-
That is illegal because std::list< T >::iterator is not what the standard calls a proper deduced context
Richard Corden : I think the appropriate part of the '03 standard is: 14.8.2.4/4. Also the standard says that this is a "non-deduced context", rather than your wording above. -
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 atypedef
alias for a real type (e.g. it might beT*
) to which it is immediately translated, so the compiler would have to build some sort of "reverse index" in order to mapT*
back tostd::list<T>::iterator
for automatic deduction ofT
to work here. But this mapping would break as soon as another class template was created that had a type member callediterator
that wastypedef
ed toT*
-- then the compiler would have two choices of what to translateT*
to, and no way to choose between them. Clearly, any automatic deduction policy that breaks when an unrelated class adds a particulartypedef
type member is much too fragile to work. -
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.j_random_hacker : +1. This will even work for plain arrays. If for some reason you really want it to work *only* for std::list, look up Boost's enable_if<> template.
0 comments:
Post a Comment