Hello everybody,

I am trying to teach my stl and after writing some basic programs I have hit a road block. I have an iterator which I am trying to pass to a function template

Here is my function template

template <class T>
void display(typename vector<T>::iterator start, typename vector<T>::iterator end){
        cout<<"My display "<<*start<<endl;
}

Here is the call to this function

    vector<int>::iterator myBeginIterator;
    vector<int>::iterator myEndIterator;

    myBeginIterator = myVector.begin();
    myEndIterator   = myVector.end();
    display(myBeginIterator,myEndIterator);

Howevert this code refuses to compile. The compilation error is

error: no matching function for call to ‘display(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >&, __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >&)

I am pretty sure this is a noob mistake. I am more of a C guy as opposed to a C++ guy. Can some one take a look at the code snippet and tell me if there is an obvious bug

Sorry it is a error -- not sure it is a beginners error, but it is an error type I think you should know about.

Solution is to write

display<int>(myBeginIterator,myEndIterator);

Reason:

What you have done is not give the compiler enough information to determine the type of the iterator. That comes about because iterator itself is a derived templated type. There is insufficient information to determine the exact type.

I have a simplified understanding of that (anyone else want to chip in with an explaination please do).

What happens is that you want a class value type. Let us write a simple one :

template<typename T>
struct A
{
    typdef int XInt;
    typedef T* XPtr;
};

Now it is perfectly possible to use XInt like this: A<double>::XInt i(20);

And obviously you can use it like this:

 template<typename T>
 void func(typename A<T>::XInt& x) { }

Everything is ok (at the moment) but the problem comes in that <T> does not actually define what you are getting as the type of XInt . You can get multiple versions of the same type, when all the compiler actually can resolve is the base type (int in this case). Thus to the compiler it is ambiguious which is forbidden. So you have
to specify e.g. int i; func<double>(i); func<int>(i);

Hope that helps, if anyone would like to make that clearer or point out the errors in my simple understanding please do.

display<int>(myBeginIterator,myEndIterator);

Wouldn't this defeat the point of using templates? Or in other words why do we have the int in the function definition?

It certainly doesn't defeat the point of using templates, that is that you write one function and have it work for multiple types.

The simple template form can be resolved. It is just here that the compiler needs some help because it cannot know which one you ment. [I have figured out that my previous example was a little obtuse: sorry]
Consider: FILE 1 with this code:

template<typename T>
struct A
{ 
    typedef int XInt;
};

Consider that you write something like this:

// this can be in a .h include file
template<typename T> void func(typename A<T>::XInt&);

// this can be in a .cpp file
template<typename T>
void func(typename A<T>::XInt& x)
  {
     std::cout<<"x == "<<x<<std::endl;
  }

BUT in another file, somewhere else you write this:

// Specialization for when <T> is double
template<>
void func(typename A<double>::XInt& x)
{
    std::cout<<"double == "<<x*x<<std::endl;
}

Now the poor compile sees you code

int main()
{
   int i;
   func(i);    
}

What can it possibly tell about the intent that you had. It can't know. Both versions correctly match, and it doesn't know that maybe in another file somewhere that will be discovered at link time, or written by another programmer linking to your library
is a specialization of func<strangeClassType>(int&). So it complains and throws an error.

You can easily replace struct A by std::vector, and you can see that there are hundreds of different std::vectorthat have identical std::vector<int>::iteratorbecause you can specialize vector by the allocator. That is why the compiler doesn't like your code. By adding func<int>(i) or func<double>(i), you have lost absolutely nothing that the template provides, you have just had to be more specific. You are only allowed to miss out the <type> if there is only one possibility, so it is obvious. If you choose to, you can still write the type in [often done to help make the code clearer.]

hope that makes more sense now.

Edited 4 Years Ago by StuXYZ

Hi Stu,

Thanks a lot for your detailed posts, I appreciate. I used a some what different approach to solve my problem.

template <class RandomAccessIterator>
  void display(RandomAccessIterator myStartIterator, RandomAccessIterator myEndIterator)

I am sure what you said probably makes sense as well, but I found this to be an easier approach. I am more of a C guy and I am trying to get my feet wet in STL.

This question has already been answered. Start a new discussion instead.