2

This question is more theoretical and the scope is different from :

Template Specialization VS Function Overloading - Explaining that the compiler does overload resolution before it even looks at specializations

Template specialization vs. Function overloading - Describing the difference between the two mechanisms

Let's get into theoretical questions:

template <typename T>
T add(T a, T b)
{
    return a + b;
}

template <>
int add<int>(int a, int b)
{
    return a + b; //Specialization
}

int add(int a, int b)
{
    return a + b; //Overloading
}

add(3,4); // in Main

1. When to use function full specialization and when to use function overloading?

Why to use template specialization since the templates are parsed twice (at template definition and at instantiation)?

On the other hand, in the case of function overloading, the answer seems pretty obvious: use it when you have a specific, particular case that needs a different logic rather than the template generic one.

2. Is the lookup process (for gcc or clang) going to choose every time the overloading candidate instead of the specialization if the form is the same? By form I mean: function name, number of arguments, argument types.

In the case of full function specialization, when the template functions are candidates, the compiler selects the template instances. Some are chosen, based on the accepted conversions (in order: strict exact match, qualification adjustment, inheritance derived to base conversion for virtual).

In the case of function overloading, among the candidate functions, select the viable ones for the call. Among the viable functions, select the best match for the call. Basically, the compiler checks the conversion strength (in order: strict exact match, qualification adjustment, int/float promotions, conversions, user conversions such as cast).

Normally, in case of ambiguity for the best viable between a template (specialization) and a non-template (overloading), the compiler selects the non-template. But why? How does the lookup mechanism work?

One factor might be the fact that the supported conversions are not the same. Example:

template <typename T>
bool isEqual(const T& a, const T& b); //generic form

template <>
bool isEqual(const string& a, const string& b); //specialization

bool isEqual(const string& a, const string& b); //overloading

bool c = isEqual ("cheers", "noroc"); //in Main, the arguments are const char *

In this case, the specialization does not match since it would require a user-defined conversion const char * -> string which is forbidden in argument deduction context. On the other hand, the overloading match since the user-defined conversion is valid here.

but what if in Main, we give strings as arguments?

string s1, s2;
bool c = isEqual (s1, s2);

Why does the compiler choose the overloading function in this case?

user3742309
  • 183
  • 2
  • 12
  • One advantage of templates: with a template you can have identical code for different types without having to duplicate the code as you would need to when you write multiple overloads. – Werner Henze May 10 '20 at 18:44
  • 1
    Name look up is a very deep hole - follow the 2 links in here: https://en.cppreference.com/w/cpp/language/lookup – Richard Critten May 10 '20 at 18:45
  • 1
    I would say consistency/expectation and therefore maintainability. If you have a template base function, you would always expect that you can specialize it, but if there is an overload like in your first example, then this will "shadow" the specialization. – t.niese May 10 '20 at 18:58
  • @WernerHenze and t.niese , so basically you say that the specialization is more used for the human factor - for maintainability, to avoid code duplication. – user3742309 May 12 '20 at 19:44
  • @t.niese see the comment above. so this means that the specialization is used for particular cases, but related to the template scope. on the other hand, the overloading can be in a totally differently scope. and we need to take care that it is compiler's favorite – user3742309 May 12 '20 at 19:45
  • 2
    @user3742309 `the specialization is ... to avoid code duplication` no, it's the template that avoids code duplication. Your `template T add(T a, T b)` can be used for any type `T` that supports `a + b`, without templates you would need to write `add` for any type you want to support, resulting in code duplication. Specialization is used to have different behavior of your template function for a certain type. And because template function support specialization, you should not use overloading for them, because that would break expectations and those harm mantainability. – t.niese May 13 '20 at 06:23

1 Answers1

1

The most fundamental difference is that overloads are found independently by name lookup, whereas specializations are found through the original template itself. The result is that overloads that appear after the call are found only by ADL:

template<class T> void f(T) {}  // #1
template<class T> void g(T t) {f(t);}
void f(int) {}                  // #2
template<> void f(char) {}      // #3
namespace N {
  struct A {};
  void f(A) {}                  // #4
}
void h() {
  f(1);       // calls #2
  g(1);       // calls #1
  g('1');     // calls #3
  g(N::A());  // calls #4
}

While overload resolution prefers a function over a function template specialization with the same signature, only an explicit specialization completely prevents implicitly instantiating the primary template (which can be selected otherwise with f<>('a')).

Another important (and the most famous) difference is that overloaded function templates behave very similarly to partial specializations (which are not available for function templates). This extends even to picking the best overload when more than one matches (via partial ordering). Of course, the limitation on name lookup pertains, so this isn’t a good means of expressing customizations that might appear after their usage; the idiomatic way to combine these features (and enable template argument deduction) is to have a “front man” function template that forwards calls to the appropriate specialization of a class template (which might be generated from a partial specialization).

Davis Herring
  • 36,443
  • 4
  • 48
  • 76
  • Thank you for the answer. Regarding the second topic "2. Is the lookup process (for gcc or clang) going to choose every time the overloading candidate instead of the specialization if the form is the same? ", will the most popular compilers ALWAYS choose the overloading function? – user3742309 May 12 '20 at 19:49
  • 1
    @user3742309: I edited to clarify that point a bit. The behavior is reliable (up to compiler bugs, of course), but applies only if the function is as good a match for every argument (which can be hard to guarantee, especially if a universal reference is involved). – Davis Herring May 12 '20 at 20:06