Thomas Paine
Thomas Paine

Reputation: 313

Wrong Template Function Being Called

I have the following two functions defined in an STL-like List Container:

// copy the specified VALUE some COUNT number of times and insert copies
// right before POS.
Iterator insert(Iterator pos, size_type count, const value_type 
            &value);

// copy the values from [FIRST, LAST) from the specified Iterators and
// place before POS.
template<class InputIt>
    Iterator insert(Iterator pos, InputIt first, InputIt last);

I then tried to test my function implementations with some arbitrary code:

std::list<int> stlList = { 1, 2, 3, 4, 5 };
MyList<int> intList;

intList.insert(intList.begin(), 5, 0); // expected call to first insert
intList.insert(intList.begin(), stlList.begin(), stlList.end()); // expected call to second insert

However, for both of them it seems like the second function is being called. I kind of see the ambiguity, since both functions have three parameters, I see how the compiler may call the wrong function. But I'm not really sure what I am missing. I have been basing my functions off of STL and as far as I can tell, they defined them in nearly the same way (STL's List Insert).

Upvotes: 1

Views: 483

Answers (2)

Sam Varshavchik
Sam Varshavchik

Reputation: 118352

template<class InputIt>
    Iterator insert(Iterator pos, InputIt first, InputIt last);

This template defines a function whose second and third parameters are the same type. You are assuming in your head that the second and the third parameters must be iterators. But there is no such requirement here, only that the second and the third parameter's type must be the same. The name of the template parameter, "InputIt", is irrelevant.

intList.insert(intList.begin(), 5, 0); // expected call to first insert

The second and the third parameter to this function call is the same type: an int. The other candidate for the overload resolution:

Iterator insert(Iterator pos, size_type count, const value_type 
        &value);

This one has different types for the second and third parameters. Although both ints can be converted here, the other template function is the better match, hence it gets selected.

Upvotes: 2

NathanOliver
NathanOliver

Reputation: 180720

The reason intList.insert(intList.begin(), 5, 0); choses

template<class InputIt>
Iterator insert(Iterator pos, InputIt first, InputIt last);

over

Iterator insert(Iterator pos, size_type count, const value_type &value);

Is because the template function produces an exact match.

5 and 0 have the same type so InputIt gets deduced as int which makes the function look like

Iterator insert(Iterator pos, int first, int last);

Where your other overload looks like

Iterator insert(Iterator pos, size_t first, int last);

As you can see no conversion is required to call the template deduced version so it is preferred over the non template overload.

You would have to cast 5 to a size_t to get it to call the non template overload or use SFINAE to only call the template overload when InputIt is really an iterator.

Upvotes: 2

Related Questions