How does C++ function template specialization work?

171 views Asked by At

I am reading C++ Primer (5th Edition), 16.5, Defining a Function Template Specialization, and confused about the example given by author, let's see the following template function:

template <typename T> int compare(const T&, const T&);

and its specialization version:

template <>
int compare(const char* const &p1, const char* const &p2)
{
    return strcmp(p1, p2);
}

Type of T will be const char *, but I don't think the function could be the specialization version of the template function, because I think const char* const &p1 can only be the specialization of T const & but const T &, I know I'm wrong, but I want to know why I am wrong.

Edit:

One thing to emphasize, if I invoke compare("hi", "mom"), it won't compile, that is to say, template <typename T> int compare(const T&, const T&) can not be initialized to int compare(const char* const &p1, const char* const &p2), I know T will be initialized with char[3] or char[4], but now that this won't compile, why won't compiler ignore this kind of initialization but choose one that will compile?

2

There are 2 answers

3
John Zwinck On BEST ANSWER

In C++, const T and T const mean exactly the same thing. Therefore const T & and T const & mean exactly the same thing.

It couldn't really be any other way, because references can never be changed to refer to something else (they are not "reseatable"). If you read T const & as "a reference which cannot be changed to refer to a different T", that's incorrect. It is "a reference to a T, which cannot be used to modify that T (and as with all references, cannot be changed to refer to a different T)."

3
Max Vollmer On

const can be either before or after a type, except for a pointer type, where it must be on the right side.

Now the tricky part here is, that T in your example is set to const char*, which is a pointer type (pointer to a const char). The template says that T has to be const, and since it's a pointer type the const in the specialization has to be put after the type, hence you get const char* const.

It becomes a bit more clear when reading it aloud from right to left:

"a const pointer to a char that is const"

//Edit:

Why can't you call compare("hi", "mom");? Because those char arrays are treated as different types by your compiler (char[3] and char[4]), but the template specifies both parameters to be the same type.

This will match the template, however it will not match your specialization (as T is now char[2]):

compare("a", "b");

This works and uses your specialized method:

const char * hi = "hi";
const char * mom = "mom";
compare(hi, mom);

//Edit2:

"I know T will be initialized with char[3] or char[4], [...] why won't compiler ignore this kind of initialization but choose one that will compile?"

Because C++ is a strongly typed language. The compiler doesn't do guess work for you, it takes the types at face value. If they don't match, they don't match. It's your job as developer to do it right.