2

I have this simple function template that's supposed to take a container as its template argument and print the contents:

template <typename T>
void print(typename T::iterator &it1,typename T::iterator &it2)
{
  while (it1 != it2) {
    std::cout<<*it1<<" ";
    ++it1;
  }
}

I'm passing an iterator range (tipically the first and the off-the-end iterators) and I added the typename keyword to the function parameters because the compiler needs to know that I'm talking about a type and not a static member.

but when I pass a vector to the function the compiler says it can't find any match for the call (the closest match being the function itself) How can it be?

vector<double> dvec;
vector<double>::iterator it_b=dvec.begin();
vector<double>::iterator it_e=dvec.end();
print_it2(it_b,it_e);

the compiler says :

template argument deduction/substitution failed
                    could not deduce template parameter T
Luca
  • 1,658
  • 4
  • 20
  • 41
  • 4
    see [Why is the template argument deduction not working here?](http://stackoverflow.com/q/1268504/3953764) – Piotr Skotnicki Aug 26 '15 at 10:43
  • 2
    It would work with `template void print(iterator &it1, iterator &it2)`. The problem (for the compiler) is that you feed it an iterator and from that it cannot figure out that `T` must be `vector`. – Bo Persson Aug 26 '15 at 10:48
  • @BoPersson yes, I tryed that and it works indeed, it just deduce the type to be vector::iterator doesn't it? – Luca Aug 26 '15 at 10:50
  • 1
    Theoretically `T` could also be some type `MySpecialContainer` that uses the same iterator class that vector does. The compiler cannot know that without instantiating ALL templates and check if any of them has a matching `iterator` member. – Bo Persson Aug 26 '15 at 10:52

1 Answers1

3

typename T::iterator is a non-deduced context. The compiler has no way of knowing which T should be deduced because it doesn't understand the semantic connection between the type member iterator and a given T. It would need to search through all types to find a match and be able to somehow disambiguate collisions. This is unreasonable, so the standard doesn't allow it.

You could supply the type explicitly:

print<vector<double>>(it_b, it_e);
print<decltype(dvec)>(it_b, it_e); //c++11

But it would probably be easier to forget about the container from which the iterator came and let the compiler deduce the iterator type:

template <typename It>
void print (It& it1, It& it2);

Maybe you have a reason to pass the iterators by reference, but it seems like you should pass by value instead:

template <typename It>
void print (It it1, It it2);    
TartanLlama
  • 63,752
  • 13
  • 157
  • 193