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?
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).
Related
// g++(5.4)
void func(int * const &) {}
void func(int *) {}
template <typename T> void tfunc(const T &) {}
template <typename T> void tfunc(T *) {}
int main()
{
int a = 0;
func(&a); // ambiguous
tfunc(&a); // unambiguous
return 0;
}
According to my another test, tfunc(&a) instantiates the first template to void tfunc(int * const &) which has the same parameter type as the first nontemplate.
So, why is the first call ambiguous but the second not?
Given two function templates that are otherwise equally as good, overload resolution will select the more specialized function template, using a procedure commonly known as partial ordering. The exact rules are pretty complicated, but essentially it tries to determine if the set of arguments template A can be called with is a (proper) subset of the set of arguments template B can be called with. If so, then A is more specialized than B, and overload resolution will prefer A.
Thus, in your case, tfunc(const T&) can be called with ~everything; tfunc(T*) can only be called with pointers. The latter is more specialized, and is therefore selected.
If you are interested in the standardese and detailed rules, see [temp.func.order] and [temp.deduct.partial].
There are some special rules in overload resolution for template functions, one of them is :
F1 and F2 are function template specializations, and the function template for F1 is more specialized than the template for F2 according to the partial ordering rules described in 14.5.6.2.
See this question about how to determine which function template is more specialized.
Here, as the second template function is more specialized, there is no ambiguation.
#include <iostream>
void func(int * const &) {}
void func(int *) {}
template <typename T> void tfunc(const T &) {std::cout << "#1\n";}
template <typename T>void tfunc(T *) {std::cout << "#2\n";}
int main()
{
int a = 0;
//func(&a); // ambiguous
tfunc(&a); // unambiguous
return 0;
}
// output: #2
Edit: Though a test in https://ideone.com/C9rF8b , we can see that the second template is chosen, not the first one as stated in the question.
Because a const pointer and a non-const pointer (i.e. T * const and T *) makes no difference if they appear in a function's parameters, and so does passing by value (by copy) and passing by const reference. That's the reason why f(&a) is ambiguous.
For the second one, since &a is resolved to int *, the second template matches better because it's more specialized (it can't accept non-pointer arguments). The first template is more general so it's not used.
If you change the first template function to this it will also be ambiguous:
template <typename T>
void tfunc(T * const &) {}
I have two templated functions with the same name (foo). Their signatures differ only in the type of the second parameter, which is dependent on the template parameter T. What has surprised me is that I can use this to overload depending on whether T::A or T::B is an existent type. Is this something which is specially provided for in the standard (if so, a reference would be much appreciated), or am I just being dense in not recognising this as basic overload resolution?
#include <iostream>
using namespace std;
template<typename T>
void foo(T t, typename T::A* a = 0) {
cout << "Had an A" << endl;
}
template<typename T>
void foo(T t, typename T::B* b = 0) {
cout << "Had a B" << endl;
}
struct HasAnAType {
typedef int A;
};
struct HasABType {
typedef int B;
};
struct HasAAndBTypes {
typedef int A;
typedef int B;
};
int main() {
HasAnAType a;
HasABType b;
HasAAndBTypes ab;
foo(a); // prints "Had an A"
foo(b); // prints "Had a B"
foo(ab); // won't compile: 'ambiguous call to overloaded function'
}
For background, I discovered this was possible when looking into the implementation of std::enable_shared_from_this, which relies on this type of overloading.
Thanks to SFINAE, the overload void foo(T t, typename T::B* b = 0) is removed when T::B doesn't exist (similar for T::A)
So when both are available, both overloads are viable, and so the call is ambiguous.
This is how the spec defines overload resolution:
Overload resolution is a mechanism for selecting the best function to
call given a list of expressions that are to be the arguments of the
call and a set of candidate functions that can be called based on the
context of the call.
the selection of the best function is the same in all cases: First, a
subset of the candidate functions (those that have the proper number
of arguments and meet certain other conditions) is selected to form a
set of viable functions. Then the best viable function is selected
based on the implicit conversion sequences needed to match each
argument to the corresponding parameter of each viable function.
For template functions, there is additional rule:
For each function template, if the argument deduction and checking
succeeds, the template arguments (deduced and/or explicit) are used to
synthesize the declaration of a single function template
specialization which is added to the candidate functions set to be
used in overload resolution. If, for a given function template,
argument deduction fails, no such function is added to the set of
candidate functions for that template.
These rules lead to what is called as SFINAE, in case of overload resolution for template functions .
You are right that this is not 'regular' overloading. It is called SFINAE. More information is here: https://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error
Consider the code:
#include <iostream>
#include <algorithm> // std::swap C++98
#include <utility> // std::swap C++11
namespace A
{
template<typename T>
struct Foo {};
template<typename T>
void swap(Foo<T> &lhs, Foo<T> &rhs)
{
std::cout << "A::swap<T>" << std::endl;
}
} /* end namespace A */
namespace std // we explicitly specialize std::swap here
{
template<> // explicit template specialization for std::swap<int>
void swap(A::Foo<int> &lhs, A::Foo<int> &rhs)
noexcept
(is_nothrow_move_constructible<A::Foo<int>>::value && is_nothrow_move_assignable<A::Foo<int>>::value)
{
std::cout << "std::swap<int>" << std::endl;
}
} /* end namespace std */
int main()
{
using std::swap;
A::Foo<int> a, b;
A::Foo<double> x, y;
swap(a, b); // ADL, expected to call std::swap<Foo<int>>, but NO
swap(x, y); // ADL, expected to call A::swap<T>, YES
}
I would expect the std::swap explicit specialization to be a better candidate in the call swap(a, b), however it seems that the overload A::swap is always preferred, i.e. the output is:
A::swap<T>
A::swap<T>
Can anyone explain why this behaviour?
Function template explicit specializations don't take part in overload resolution. Only function declarations synthesized from primary templates are considered. If one such function is chosen as the best viable function by the overload resolution process, an explicit specialization of the corresponding primary template will be used if suitable.
In this case, overload resolution needs to choose between a function declaration synthesized from your swap function template overload taking foo<T>& and one synthesized from the std::swap primary template taking T&.
None of these two functions can be chosen over the other based on conversions (they have the same function parameters), both are template specializations, so partial ordering of function templates is considered, which yields your swap function template as more specialized, so the function declaration synthesized from your swap overload wins.
Explicit function template specializations never change which function template or overload is called, only the implementation of the template if it is called.
Overload resolution ignore specializations (as opposed to overloads, which can look a lot like partial specialization to someone unfamiliar with C++ function template quirks).
I can imagine why: mixing both overload and template specialization selection rules would make the rules even harder to follow and get right.
In general, it is rarely a good idea to specialize a function template: overloads, or dispatching to a template class, is usually better.
Note that the language talks about 'more specialized' in overload resolution: do not confuse this with 'template specialization': they are distinct concepts that unfortunetally share a word.
As mentioned in other answers, the reason is that the signature of the
explicit function specialization is not taking part in overload
resolution.
A simple rule of thumb for explicit specializations is that they change the the definition that will be used when it's primary template is called with the specific template arguments.
template <typename T> void foo (T) {
// definition used for 'foo' when T is not 'int'
}
template <> void foo<int> (int) {
// definition used for 'foo' when T is 'int'
}
The compiler performs the following steps when selecting the best swap (I'll ignore exception specifications for brevity):
namespace A
{
template <typename T> struct Foo { };
template <typename T> void swap (Foo<T> &, Foo<T> &);
}
namespace std
{
// swap provided by the STL
template <typename T> void swap (T &, T &);
// explicit specialization of std::swap
template <> void swap (Foo<int> &, Foo<intT> &) { }
}
Specializations of the primary templates are generated for both swaps:
13.3.1p7: In each case where a candidate is a function template,
candidate function template specializations are generated using
template argument deduction (14.8.3, 14.8.2). Those candidates are
then handled as candidate functions in the usual way.
NB: The explicit specialization is not part of this.
For swap(a,b) the candidate set used by overload resolution will
contain the following generated function template specializations:
A::swap(Foo<int>&, Foo<int>)&);
std::swap(Foo<int>&, Foo<int>)&);
Both are generated template specializations and both have exactly the same conversion sequences for the arguments so to determine which template to use the following bullet in the Best Viable Function says:
13.3.3p1b7: F1 and F2 are function template specializations, and the
function template for F1 is more specialized than the template for
F2 according to the partial ordering rules described in 14.5.6.2.
Partial ordering comes down to comparing the function parameter lists to find which is more specialized. In this example, Foo<T> is more specialized than T and so swap(Foo<T>&, Foo<T>&) is considered a better match than swap(T&,T&). The result is that A::swap is selected and so the explicit specialization of std::swap is ignored.
If the code is changed so the explicit specialization is for A::swap rather than std::swap then as A::swap wins overload resolution, then the explicit specialization will be used:
namespace A
{
template <typename T> struct Foo { };
template <typename T> void swap (Foo<T> &, Foo<T> &);
// explicit specialization of A::swap
template <> void swap (Foo<int> &, Foo<intT> &) { }
}
If I thought I knew anything about C++ then it was that you can't overload functions by return type.
So can anyone explain what is going on here please?
class A { public: typedef int _foo; };
class B {};
template<class T>
typename T::_foo Foo(int)
{
cout << "Foo(int)\n"; return typename T::_foo();
}
template<class T>
typename T Foo(char)
{
cout << "Foo(char)\n"; return typename T();
}
int main()
{
Foo<A>(0); // Writes "Foo(int)", as expected.
Foo<B>(0); // Writes "Foo(char), expected error unable to compile template.
return 0;
}
There are two classes A and B. A defines typedef _foo, B does not. There are two overloads of function template Foo, Foo(int) and Foo(char). Foo(int) returns T::_foo, Foo(char) returns T.
Foo(0) is then called twice. This is an exact match for Foo(int) so I would expect Foo<A>(0) to compile ok, and Foo<B>(0) to fail to compile since B does not define the type _foo used in the template.
What actually happens is that Foo<B>(0) completely ignores Foo(int) and instantiates Foo(char) instead. But by the normal rules of overload resolution Foo(0) is clearly an exact match for Foo(int), and the only thing that makes Foo(char) a more viable match is the return type which should not be considered.
To verify that it is the return value that is affecting the overload resolution just add this:
template<class T>
void Bar(int) { typename T::_foo a; cout << "Bar(int)\n"; }
template<class T>
void Bar(char) { cout << "Bar(char)\n"; }
Bar<A>(0); // Writes "Bar(int), as expected.
//Bar<B>(0); // Error C2039: '_foo' : is not a member of 'B', as expected.
This makes it clear that in the absence of the return value Foo(int) is indeed the correct overload, and that if the template cannot resolve the types used from its template argument that failure to compile is the normal outcome.
You're not overloading on return type, you're specializing a function template and when the Foo<B>(int) specialization forms the invalid type B::_foo that specialization is removed from the overload set by SFINAE, leaving the Foo<B>(char) function as the only viable function.
In more detail, the call to Foo<A>(0) first performs name lookup to find all the Foo names in scope, then instantiates any function templates to find the overload candidates, then overload resolution chooses the best match.
The step of instantiating the function templates produces these two function declarations:
int Foo<A>(int);
A Foo<A>(char);
Overload resolution chooses the first one as the best match.
However when calling Foo<B>(0) the instantiations produce these declarations:
<invalid type> Foo<B>(int);
B Foo<B>(char);
The first declaration is not valid, so there is only one candidate for overload resolution, so that is the one that gets called.
In your Bar example the invalid type that gets formed during instantiation is not in "the immediate context" of the function declaration (it's in the function definition i.e. body) so SFINAE does not apply.
template<class T>
typename T::_foo Foo(int);
template<class T>
typename T Foo(char);
So your code declares this overloaded function. That's nice.
Foo<A>(0);
In this case, the compiler tries to fill out the template for the prototypes declared above, which would be:
int Foo(int);
A foo(char);
And since you're passing an integer as a parameter, the first is a better match, so the compiler uses that one.
Foo<B>(0);
Again the compiler sees this line and tries to fill out the template for the prototypes, but...
WTFDOESNTMAKESENSE?!?!? Foo(int);
A foo(char);
So clearly, the first one doesn't even make sense, so it discards that and uses the second overload. This actually has nothing to do with return types, it has to do with how template prototypes are filled out before it decides which function you mean. Here's your example rearranged to clarify:
template<class T>
int foo(T::_foo) {}
template<class T>
int foo(char) {}
int main() {
foo<A>(0); //uses the first, `int foo(int)` better than `int foo(char)`
foo<B>(0); //uses the second, because the first doesn't work with B.
This is called SFINAE, and note that it only works in very particular circumstances in template parameters, return types, and function parameters, but not the function body itself. This is why your "verification" caused an error, because it can't tell that one of the functions is invalid from the prototype, and the prototype is the only thing considered when it's deciding between overloads.
template <class T>
void max (T &a ,T &b)
{}//generic template #1
template<> void max(char &c, char &d)
{} //template specializtion #2
void max (char &c, char &d)
{}//ordinary function #3
what is difference between 1 ,2, and 3?
is a template function
is a total specialization of the previous template function (doesn't overload!)
is an overload of the function
Here is an excerpt from C++ Coding Standards: 101 Rules, Guidelines, and Best Practices:
66) Don't specialize function templates
Function template specializations never participate in overloading: Therefore, any specializations you write will not affect which template gets used, and this runs counter to what most people would intuitively expect. After all, if you had written a nontemplate function with the identical signature instead of a function template specialization, the nontemplate function would always be selected because it's always considered to be a better match than a template.
The book advises you to add a level of indirection by implementing the function template in terms of a class template:
#include <algorithm>
template<typename T>
struct max_implementation
{
T& operator() (T& a, T& b)
{
return std::max(a, b);
}
};
template<typename T>
T& max(T& a, T& b)
{
return max_implementation<T>()(a, b);
}
See also:
Why Not Specialize Function Templates?
Template Specialization and Overloading
The matching rules for template parameters subtly differ from that of overloaded functions. An example of what differs can be seen when you try to invoke max() with arguments of different tyoes:
max(1,'2');
This will match the overloaded function, but neither the base template nor the specialization.