Hello I have this code from C++ primer 5th ed:
Primary function template:
// first version; can compare any two types
template <typename T>
int compare(T const& x, T const& y)
{
std::cout << "compare(T const&, T const&)\n";
if(std::less<T>()(x, y))
return -1;
if(std::less<T>()(y, x))
return 1;
return 0;
}
A specialization for character arrays:
// second version to handle string literals
template <unsigned N, unsigned M>
int compare(char const(&ar1)[N], char const(&ar2)[M])
{
std::cout << "compare(char const(&)[N], char const(&)[M])\n";
return strcmp(ar1, ar2);
}
// special version of compare to handle pointers to character arrays
template <>
int compare(const char* const &p1, const char* const &p2)
{
std::cout << "compare(char const* const&, char const* const&)\n";
return strcmp(p1, p2);
}
int main()
{
const char *p1 = "hi", *p2 = "mom";
compare(p1, p2); // calls the third version (pointers to character strings)
compare("hi", "mom"); // calls the template with two nontype parameters
compare("high", "HIGH"); // error: call ambiguous
std::cout << "\nDone!\n";
}
I have some questions:
Is the version of compare with reference to arrays parameters a specialization or an overload? I think it is a specialization because its parameter list must match the one of the Primary function template compare. is it right?
The program works fine until I pass two arrays of characters or two literal character string with Same lengths. in which case the compiler cannot resolve the call like in my call compare("high", "HIGH");.:
Does this mean it fails because the version with arrays parameters is not viable? -because I guess that the Size of an array is a part of its type thus passing two arrays with different sizes yields two different types consequently this version is not viable?
The output of my compiler:
error: call of overloaded ‘compare(const char [5], const char [5])’ is ambiguous
candidate: ‘int compare(const T&, const T&) [with T = char [5]]’|
candidate: ‘int compare(const char (&)[N], const char (&)[M]) [with unsigned int N = 5; unsigned int M = 5]’
With respect to your first question: the function is an overload and not a specialization. There is no way to partially specialized a function template to start with. Beyond that, a specialization would mention an empty template parameter list. For example, the version for char const* is a specialization:
template <>
int compare(char const* x, char const& *);
With respect to your second question: it seems the compiler came to the conclusion that the first overload and the second overload are equally good. I'm not quite sure why that is as the version taking array references seems better. Adding another overload resolves that problem:
template <unsigned N>
int compare(char const(&ar1)[N], char const(&ar2)[N])
{
std::cout << "compare(char const(&)[N], char const(&)[N])\n";
return strcmp(ar1, ar2);
}
The version with two array sizes would be viable as well. It is just that the other overload is good, too. Instead of adding an overload, you could constrain the first version so it can't be used for arrays:
template <typename T>
std::enable_if_t<!std::is_array_v<T>, int> compare(T const& x, T const& y)
{
std::cout << "compare(T const&, T const&)\n";
if(std::less<T>()(x, y))
return -1;
if(std::less<T>()(y, x))
return 1;
return 0;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With