Section 16.3 of C++ Primer (5th edition) - Overloading and Templates -, teaches the function matching procedure in the presence of candidate function template(s) instantiations.
Here are the declaration for the function templates used in this section:
using std::string;
template <class T> string debug_rep(const T &); /* 1 */
template <class T> string debug_rep(T *); /* 2 */
// definitions not relevant for the questions
First example
string s("SO");
debug_rep(&s);
it is then said that the generated instantiations will thus be:
debug_rep(const string *&)
(withT
bound tostring *
)debug_rep(string *)
Q1 Is it correct for #1 ? Should not it instantiate debug_rep(string* const &)
instead?
Second example
const string *sp = &s;
debug_rep(sp); //string literal type is const char[10]
it is then said that the generated instantiations will thus be:
debug_rep(const string *&)
(withT
bound toconst string *
)debug_rep(const string *)
Thus, both instantiated candidate would provide an exact match, selection being made on the more specialized template (-> #2)
Q2.1 Is it correct for #1 ? Should not it instantiate debug_rep(const string* const &)
?
Q2.2 Assuming the instantiated function is the one just above, can we affirm it is not an exact match any more ?
Third example
debug_rep("SO world!"); //string literal type is const char[10]
it is then said that the generated instantiations will thus be:
debug_rep(const T &)
(withT
bound tochar[10]
)debug_rep(const string *)
Thus, both instantiated candidate would provide an exact match, selection being made on the more specialized template (-> #2)
Q3.1 Is the type deduced for T
correct in #1 ? Should not it be const char[10]
instead ?
Q3.2 Assuming the deduced type for T
is actually the one just above, can we affirm it is not an exact match any more ?
EDIT: Thanks to Alf answer, and its elegant trick to conserve complete information about a type while using
typeid
, I was able to write a program that addresses most of my questions (changing fromstd::string
toint
for output readability.)The complete code can be edited and run rextester online IDE.
Let's define a few classes and methods:
example 1
Running:
Displays:
Q1: we can remark that, when we call force_1, instantiating a template corresponding to #1, the argument type is
int * const &
, so the book is not correct, and the instantiated candidate #1 would bedebug_rep(int* const &)
example 2
Running:
Displays:
Q2.1: Calling
force_1
, we remark that the argument type will beint const * const &
, so the book is missing const qualification on the reference. The instantiated candidate will actually be:debug_rep(const int * const &)
Q2.2 The second candidate being
debug_rep(const int *)
, it is an exact match forip
(which is a pointer to constant integer). To check if the first candidate has a lower rank, let's write:If we try to compile:
There is a compilation error for ambiguous call: So the answer to Q2.2 is NO, it is still an exact match ! For the templated version, the compiler actually uses the rule regarding the most specialized template to resolve the ambiguity.
Even if there is a mistake in the deduced candidate, the book is correct regarding the fact that this example illustrates overload resolution using the most specialized template.
example 3
Running:
Displays:
Q3.1 The type deduced for
T
by CL is array of const integer, so the book would be mistaken.BUT the result is inconsistent with GCC or Clang, that would output:
The interesting part being:
[forced 1] T type is:4TypeIA3_iE
meaning that they deduce
T
as an array of 3 non-const integers (because _i, not _Ki), which would agree with the book.I will have to open another question for this one, I cannot understand the type deduction operated by GCC and Clang...