Reputation: 7506
Here's what C++ Primer 5th says:
Version 1:
template <typename T> int compare(const T&, const T&);
Version 2:
template<size_t N, size_t M> int compare(const char (&)[N], const char (&)[M]);
A specialization of Version 1:
template <> int compare(const char* const &p1, const char* const &p2);
For example, we have defined two versions of our
compare
function template, one that takes references to array parameters and the other that takesconst T&
. The fact that we also have a specialization for character pointers has no impact on function matching. When we call compare on a string literal:compare("hi", "mom")
both function templates are viable and provide an equally good (i.e., exact) match to the call. However, the version with character array parameters is more specialized (§ 16.3, p. 695) and is chosen for this call.
The book says "both provide an equally good match", so then I thought putting Version 1 and its specialization should compile well. But it didn't.
So "provide an equally good match" doesn't mean it can compile? The book plays a trick on me?
Original code snippet link that I didin't understand why can't compile: https://wandbox.org/permlink/oSCDWad03nELC9xs
Full context screenshot (I've boxed the most related part, sorry to post such a big pic here).
Upvotes: 4
Views: 280
Reputation: 652
The compiler is unable to match it to one of the existing templates. If you read the section 16.5 carefully you will understand that it would call the second version of the template class.
The function call has 2 different types of parameters const char[3]
and const char [4]
compiler is unable to find a template specialization that takes 2 different data types as parameters.
The code below is one of the solutions.
#include <iostream>
#include <string>
using namespace std;
template <typename T> int compare(const T&, const T&) {
cout << "const T" << endl;
return 3;
}
template<size_t N, size_t M>
int compare(const char (&p)[N], const char (&q)[M]) {
cout<<p<<" "<<q<<endl;
return 3;
}
int main()
{
compare("hi", "mom");
}
The other solution is as below. It takes 2 different types and access the variables.
#include <iostream>
#include <string>
using namespace std;
template <typename T> int compare(const T&, const T&) {
cout << "const T" << endl;
return 3;
}
template <typename T1, typename T2>
int compare(const T1&p, const T2&q){
cout<<p<<" "<<q<<endl;
return 3;
}
int main()
{
compare("hi", "mom");
}
Upvotes: 0
Reputation: 180594
C-style strings are not pointers, they are arrays. When template type deduction happens, it deduces T
as either const char[3]
or const char[4]
. Since those conflict the compiler is unable to deduce T
and it stops there.
template<>
int compare(const char* const &p1, const char* const&p2) {
cout << "const char* const" << endl;
return 3;
}
won't be called because it relies on T
being deduced and matching const char*
and the compiler was not able to deduce T
. A specialization is not a overload, it is a recipe for that specific T
. If T
can't be deduced then the specialization, even it it were to be a valid overload, won't be called.
If you were to overload the function instead of providing a specialization then it would compile with:
int compare(const char* const &p1, const char* const&p2) {
cout << "const char* const" << endl;
return 3;
}
Upvotes: 2
Reputation: 12757
You are passing to the template function two parameters of different types (the type of "hi"
is const char [3]
and the type of "mom"
is const char [4]
), so the compiler is not able to find a T
that matches both types.
It's the same error that you would obtain calling std::min(0, 1U)
; std::min()
(one of its overload) expects two arguments of the same type, as your compare()
function does.
A possible solution to your problem is to accept parameters of different types:
template <typename T1, typename T2>
int compare(const T1&, const T2&);
This will work without editing the body of your function.
Upvotes: 2