3

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]’
  • So how could I disambiguate this call? and please guide me about my guesses. Thanks
Maestro
  • 2,512
  • 9
  • 24

1 Answers1

4

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;
}
Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • 1
    The last version you've added with `std::enable_if_t` is really good. But I am still learning, Thank you it solves the problem. and thanks for clarifying my doubts. – Maestro Dec 23 '20 at 21:58
  • 1
    Great answer! About why the "the first overload and the second overload are equally good", I believe that determination is according to "best viable function" cases listed here: https://en.cppreference.com/w/cpp/language/overload_resolution#Best_viable_function – Pascal Getreuer Dec 23 '20 at 22:04
  • @PascalGetreuer: sure... It is just that I can’t keep 12 rules with interesting details in my head! I guess, in the end neither version needs conversions and both are just as good - except that this diesn’t explain why the version with equal array sizes gets preferred. – Dietmar Kühl Dec 23 '20 at 22:11
  • @DietmarKühl that's a good point on the equal array size overload being preferred. I don't see anything in that list to explain that. – Pascal Getreuer Dec 23 '20 at 22:26