0

I have overloaded << to print the contents of a pair, in two different forms (see code below). The first form is specific for the pair type defined. The second is templated, for any pair. Any of the two is ok for my pair type. When both prototypes precede the definition of main, the first one (specific) is used, regardless of the order of the prototypes. Only when the prototype for the first is commented, is the second used.

Why is the ambiguity resolved in this way, deciding which is the appropriate function to use?

#include <iostream>
#include <map>

using namespace std;

typedef pair<string, char> pair_t;

ostream& operator<<(ostream& os, const pair_t& p);   // First form, specific

template<class first_class, class second_class>
ostream& operator<<(ostream& os, const pair<first_class, second_class>& p);   // Second form, generic

int main(void) {
        pair_t p2;
        p2 = make_pair("Fer", 'C');
        cout << p2 << endl;
        return 0;
}

ostream& operator<<(ostream& os, const pair_t& p)
{
    os << p.first << " obtained \'" << p.second << "\'";
    return os;
}

template<class first_class, class second_class>
ostream& operator<<(ostream& os, const pair<first_class, second_class>& p)
{
    os << "(" << p.first << ", " << p.second << ")";
    return os;
}

1 Answers1

2

std::pair has an overloaded converting constructor which is:

template< class U1, class U2 >
constexpr pair( const pair<U1, U2>& p );

You did this:

p2 = make_pair("Fer", 'C');

the call std::make_pair("Fer", 'C') returns an object of type std::pair<const char[4], char> which is convertible to std::pair<std::string, char>.

Passing it to std::cout, will require overloaded resolution to instantiate the overloaded function templates creating a set of function specialization:

ostream& operator<<(ostream& os, const std::pair<std::string, char>& p)
ostream& operator<<(ostream& os, const std::pair<std::string, char>& p);    //compiler generated template specialization

The rules for which one may be selected is captured here

For each pair of viable function F1 and F2, the implicit conversion sequences from the i-th parameter to i-th argument are ranked to determine which one is better (except the first argument, the implicit object argument for static member functions has no effect on the ranking)

F1 is determined to be a better function than F2 if implicit conversions for all arguments of F1 are not worse than the implicit conversions for all arguments of F2, and

  1. there is at least one argument of F1 whose implicit conversion is better than the corresponding implicit conversion for that argument of F2
  2. or. if not that, (only in context of non-class initialization by conversion), the standard conversion sequence from the return type of F1 to the type being initialized is better than the standard conversion sequence from the return type of F2
  3. or, if not that, F1 is a non-template function while F2 is a template specialization
  4. or, if not that, F1 and F2 are both template specializations and F1 is more specialized according to the partial ordering rules for template specializations
WhiZTiM
  • 21,207
  • 4
  • 43
  • 68
  • Seems to hit the nail in the head. With this pointer I could read a little more. [This](http://stackoverflow.com/a/23424604/2707864) provides a similar answer, plus it gives the original source in the standard. – sancho.s ReinstateMonicaCellio Oct 12 '16 at 10:32