1
votes

I recently had a question when implementing my own Vector container for study purpose.

In my Vector class a non-template member function and a template member function with the same name are declared (insert function). In case of conflict (when some template specialization matches the non-template function signature exactly), compiler gave me error....

Suppose that my vector class has 2 functions called insert:

/* Vec.h */
template <class T> class Vec {
public:
    iterator insert ( iterator position, size_type n, const value_type& val );

    template <class InputIterator>
    iterator insert (iterator position, InputIterator first, InputIterator last);
}
#include "Vec.hpp"

In Vec.hpp:

/* Vec.hpp */
template <class T>
typename Vec<T>::iterator Vec<T>::insert( iterator position, 
                                          size_type n, 
                                          const value_type& val)
{
    /* Implementation */
}

template <class T> template <class InputIterator>
typename Vec<T>::iterator Vec<T>::insert( iterator position,
                                          InputIterator first,
                                          InputIterator last )
{
    /* Some code ... */

    /* Copy the element */
    while( first != last )
    {
        new ( position + idx ) T(*first);
        ++idx;
        ++first;
    }

    /* Some other code ... */
}

In main.cpp:

int main()
{
    Vec<int> myVec;
    MyVec.push_back(5);
    myVec.insert( myVec.begin(), 3, 3);
}

Compiler error:

../Vec.hpp: In instantiation of ‘T* Vec<T>::insert(Vec<T>::iterator, InputIterator, InputIterator) [with InputIterator = int; T = int; 
Vec<T>::iterator = int*]’:
../main.cpp:128:45:   required from here
../Vec.hpp:306:30: error: invalid type argument of unary ‘*’ (have ‘int’) 
new ( position + idx ) T(*first);
                          ^

It seems like compiler tries to use the template insert function instead of non-template one. This is contradict with what I thought. And it looks like although I did not provide the argument list for insert function:

myVec.insert<int*>

The compiler implicitly instantiate the template insert function with int type.

In member templates from cppreference, it also says that the compiler should use non-template one in this case.(Please refer to Member function templates section)

My environment: Ubuntu 16.04 LTS, g++ (Ubuntu 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609

Please

  1. explain why the compiler uses template member function

  2. Provide solution to the above issue. so that when I do insert( iterator, int, int) or other similar function calls such as insert( iterator, unsigned int/long, unsigned int/long), it will call the proper member function.

Thanks everyone's help. I really appreciate it!!

1
In future, please post code all in one piece. No assembly required. Read: minimal reproducible example As it is, where are the #includes?Jive Dadson

1 Answers

3
votes
myVec.insert( myVec.begin(), 3, 3);

First thing that happens is that it finds all possible overloads:

iterator insert ( iterator position, size_type n, const value_type& val );
template <class InputIterator>
iterator insert (iterator position, InputIterator first, InputIterator last);

then it does template argument deduction. In this case, InputIterator=int is valid.

iterator insert ( iterator position, size_type n, const int& val );
template <>
iterator insert (iterator position, int first, int last);

as both 3 and 3 are of type int.

Now it does ocerload resolution. The template function here has zero conversions. The non-template one requires converting int to size_type.

The one with zero conversions wins. If they tied, then the non-template function wins on ties; but zero conversion wins.

Note that the iterator type is int not int*; this causes the body to fail to compile, because int cannot be dereferenced.