Home > Enterprise >  function templates overloading versus fully-specializing
function templates overloading versus fully-specializing

Time:10-27

Hello I have this example:

#include <iostream>

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

template <typename T>
int compare(T*, T*);

template <>
int compare(char const * const&, char const* const&);

template <unsigned N, unsigned M>
int compare(char const (&)[N], char const(&)[M]);

template <unsigned N>
int compare(char const (&)[N], char const(&)[N]);


template <typename T>
int compare(T const& lhs, T const& rhs){
    std::cout << "compare(T const&, T const&)\n";

    if(std::less<T>()(lhs, rhs))
        return -1;
    if(std::less<T>()(rhs, lhs))
        return 1;
    return 0;
}

template <typename T>
int compare(T* p1, T* p2){
    std::cout << "compare(T*, T*)\n";
    if( std::less<T>()(*p1, *p2) )
        return -1;
    if( std::less<T>()(*p2, *p1) )
        return 1;
    return 0;
}

template <>
int compare(char const * const& p1, char const* const& p2){
    std::cout << "compare(char const * const &, char const * const &)\n";
    return strcmp(p1, p2);
}

template <unsigned N, unsigned M>
int compare(char const (&ra)[N], char const(&rb)[M]){
    std::cout << "compare(char const(&)[N], char const(&)[M])\n";
    return strcmp(ra, rb);
}

template <unsigned N>
int compare(char const (&ra)[N], char const(&rb)[N]){
    std::cout << "compare(char const(&)[N], char const(&)[N])\n";
    return strcmp(ra, rb);
}

int main(){

    int a = 10, b = 57;
    char const* const cp1 = "Hello";
    char const* const cp2 = "World";

    std::cout << compare(a, b) << '\n';
    std::cout << compare(&a, &b) << '\n';
    std::cout << compare(cp1, cp2) << '\n';
    // std::cout << compare("Hi", "Hi") << '\n'; // error: ambiguous
    // std::cout << compare("Hi", "World!") << '\n'; // error: ambiguous

    cout << '\n';
}
  • Why the call to compare passing two arrays of of constant characters is ambiguous even the arrays of different lengths?

  • In fact the second overload that has a single non-type parameter N is just for compatibility with C 11 because on C 14 and above I can use std::enable_if. please

  • Why also passing compare(cp1, cp2); invokes compare(T*, T*) and not compare(char const* const&, char const * const&)?

  • One final question: Does my order of declaring the function templates here affects which function is preferred? Thank you.

CodePudding user response:

Question 1

Why the call to compare passing two arrays of of constant characters is ambiguous even the arrays of different lengths?

Answer 1

This is because when you write compare("Hi", "World!"); there are two version that can be used(equally good). First version is

template <typename T>
int compare(T*, T*);

And the second version is:

template <unsigned N, unsigned M>
int compare(char const (&ra)[N], char const(&rb)[M]);

Important Note

Note that the version:

template <>
int compare(char const * const& p1, char const* const& p2);

is a specialization and so it does not take part in overloading.To be more specific remember that:

Specializations instantiate a template; they do not overload it. As a result, specializations do not affect function matching.

So the answer(at least to your first question) given by @Aconcagua is incorrect.

Question 2

Why also passing compare(cp1, cp2); invokes compare(T*, T*) and not compare(char const* const&, char const * const&)?

Answer 2

This is because the version:

template <typename T>
int compare(T*, T*);

will be chosen for "all pointers" and more importantly it can take part in overloading while the version

template <>
int compare(char const * const& p1, char const* const& p2);

is a specialization and hence does not take part in overloading.

Question 3

Does my order of declaring the function templates here affects which function is preferred?

Answer 3

No

CodePudding user response:

Why the call to compare passing two arrays of of constant characters is ambiguous even the arrays of different lengths?

Because both of

template <>
int compare(char const * const&, char const* const&);

template <unsigned N, unsigned M>
int compare(char const (&)[N], char const(&)[M]);

match in both cases, and in second case the third overload joins in as well (you might have specialised as template <unsigned N> compare<N, N>(...) to avoid ambiguity at least between those latter two.

Why also passing compare(cp1, cp2); invokes compare(T*, T*) and not compare(char const* const&, char const * const&)?

[obsolete]

This is better (and correctly) explained in Frank's answer, see there...

By accepting pointers by value (char const* px) you'd specialise the the other base template, though, and you would have seen the desired result.

One final question: Does my order of declaring the function templates here affects which function is preferred?

No. All overloads that are known at the time of calling the function are considered, no matter in which order they have been declared. If that wasn't the case it would be nearly impossible (at least only with significant research work) to predict which overload gets called if these are imported (possibly indirectly!) via different headers.

  • Related