C++ primer 5th ed. function template overloading

106 Views Asked by At

In the book C++ Primer, there is an example about function template overloading:

// print any type we don't otherwise handle
template <typename T> string debug_rep(const T &t)
{
    cout << "debug_rep(T const&)\n";
    ostringstream ret; // see § 8.3 (p. 321)
    ret << t; // uses T's output operator to print a representation of t
    return ret.str(); // return a copy of the string to which ret is bound
}

// print pointers as their pointer value, followed by the object to which the pointer points
// NB: this function will not work properly with char*; see § 16.3 (p. 698)
template <typename T> string debug_rep(T *p)
{
    std::cout << "debug_rep(T*)\n";
    ostringstream ret;
    ret << "pointer: " << p << '\n';         // print the pointer's own value
    if (p)
        ret << " " << debug_rep(*p); // print the value to which p points
    else
        ret << " null pointer";      // or indicate that the p is null
    return ret.str(); // return a copy of the string to which ret is bound
}

If we call debug_rep with a pointer:

cout << debug_rep(&s) << endl;

both functions generate viable instantiations:

  • debug_rep(const string* &), which is the instantiation of the first version of debug_rep with T bound to string*

  • debug_rep(string*), which is the instantiation of the second version of debug_rep with T bound to string*

The instantiation of the second version of debug_rep is an exact match for this call.

The instantiation of the first version requires a conversion of the plain pointer to a pointer to const. Normal function matching says we should prefer the second template, and indeed that is the one that is run.

But if I declare the pointer to string as const although there's no conversion the second version is always chosen:

    string const s("hi"); // const
    cout << debug_rep(&s) << '\n';

So I think it is a mistake in the book and I think because the version takes a pointer is preferred because we pass a pointer being const or not (T will be deduced as std::string const* or std::string*).

What do you think?

1

There are 1 best solutions below

2
On BEST ANSWER

The book is wrong.

In the first example, the instantiation generated is not debug_rep(const string* &), it is debug_rep(string* const&). That is, const qualifies the pointer, not the thing pointed to. (This would be more obvious if the book used right const; that is, template <typename T> string debug_rep(T const& t) for the first function template.)

Indeed, T and T const& have equal priority as function template overloads; where they form an overload set it will be ambiguous. The reason T* is chosen over T const& is that it is more specialized; simply put, an arbitrary T* can be passed to a function taking T const&, while an arbitrary T const& cannot be passed to a function taking T*.