C++ function template specialization and overloading - c++

Considering this code:
template <class T>
void f(T p) { //(1)
cout << "Second" << endl;
}
template <>
void f(int *p) { //(2)
cout << "Third" << endl;
}
template <class T>
void f(T* p) { //(3)
cout << "First" << endl;
}
A call such as int *p; f(p); will output First.
If the order of the declarations is changed, like this:
template <class T>
void f(T* p) { //(3)
cout << "First" << endl;
}
template <class T>
void f(T p) { //(1)
cout << "Second" << endl;
}
template <>
void f(int *p) { //(2)
cout << "Third" << endl;
}
the same call (int *p; f(p);) will output Third.
I read about the way in which function template overload resolution takes places: first the resolution considers only non-template functions and the underlying base templates. After the "most specialized" one is chosen, if it is a template function and it has a specialization for the parameters which were deduced (or explicitly specified), that specialization is called.
Now my question is: how it is decided for which underlying base template a function is a specialization? In my example, for which function template overload ( (1) or (3) ) is (2) a specialization?
My guess is that when a specialization is declared, the templates already declared are considered, and from those the most "specialized" (whose parameters are "closest" to this specialization) is chosen. Is this correct? Also, could you point me to where this is specified in the standard?

It prints "First" because the order of declaration affects which template you in fact specialize.
Your example has two function templates, which overload the same name. In the first case, you specialize void f(T p), because it's the only template seen so far.
In the second case, it's void f(T* p) that's specialized. So yes, your guess is correct. The specifics are at [temp.deduct.decl/1]:
In a declaration whose declarator-id refers to a specialization of a
function template, template argument deduction is performed to
identify the specialization to which the declaration refers.
Specifically, this is done for explicit instantiations, explicit
specializations, and certain friend declarations. [...]
And that includes the partial ordering of the function templates. However, partial ordering only applies to the available function template declarations at the point you introduce your specialization.
And the standard warns at [temp.expl.spec/7]:
The placement of explicit specialization declarations for function templates, [...] , can affect whether a program is well-formed
according to the relative positioning of the explicit specialization
declarations and their points of instantiation in the translation unit
as specified above and below. When writing a specialization, be
careful about its location; or to make it compile will be such a trial
as to kindle its self-immolation.

Related

c++ explicit specialization can not access primay template member but can access partial specialization member?

#include <iostream>
using namespace std;
template<class T, int I> // primary template
struct A {
void f(); // member declaration
};
template<class T, int I>
void A<T,I>::f() { } // primary template member definition
// partial specialization
template<class T>
struct A<T,2> {
void f();
void g();
void h();
};
// member of partial specialization
template<class T>
void A<T,2>::g() {
cout << "partial g()" << endl;
}
template<class T>
void A<T,2>::h() {
cout << "partial h()" << endl;
}
// explicit (full) specialization
// of a member of partial specialization
template<>
void A<char,2>::h() {
cout << "explicit h()" << endl;
}
int main() {
A<char,2> a2;
a2.f(); // ERROR, partial can not access primary member
a2.g(); // OK, uses partial specialization's member definition
a2.h(); // OK, explicit h() being called.
}
I went thorugh cpp reference, It says
"Members of partial specializations are not related to the members of
the primary template."
So understandably, a2 can not access member of primary specialization a2.f() ?
My Questions are
how is the relationship between member of partial specialization and member of explicit specialization ?
Why a2 can access the member of partial specialization a2.g() here ?
It is important to realize that a class template is not a class, but only a blueprint for one.
A<char,2> matches the specialized blueprint, so it has f,g,h member functions. Contents of the primary template are completely ignored.
Because A is a template class, its methods are instantiated only when actually called and only for those concrete template arguments because instantiation of A is a class, thus it has only one set of methods.
Since you did not define any A<char,2>::f, the linker reports undefined reference error.
There is a definition of A<char,2>::g available by instantiating template<class T> void A<T,2>::g() function - that is an ordinary method, not a function template.
For the same reason, A<char,2>::h also compiles - there is a definition for this function, nothing more is required.
In a nutshell, the compiler will only look for the definitions it needs, if it finds a matching template, it will generate the definitions. Otherwise it will mark the symbol as missing and it is your responsibility that the linker will have it available.

Rule for which function overload to specialize

Consider the code:
#include <iostream>
template <typename T>
void f(T)
{
std::cout << "Version 1" << std::endl;
}
template <typename T>
void f(T *)
{
std::cout << "Version 2" << std::endl;
}
template <>
void f<>(int *)
{
std::cout << "Version 3" << std::endl;
}
int main()
{
int *p = nullptr;
f(p);
return 0;
}
This code will output Version 3. What is happening is that function overloading rules look at the first two versions of void f (the third version is a specialization and does not participate in the overload), and decides that the second version is the better version. Once that decision is made, we then see if any specializations exist for the second version. There is, and we use it.
My question, then, is: How did the compiler know that my explicit specialization was a specialization of the second overload and not the first one? I have not provided it with a template parameter for it to make that choice. Is it simply the case that deciding which function to specialize follows a similar/the same rule as deciding which overload to call (if it were calling the function)? That would make some sense...
There is that example in template_argument_deduction#Explicit_instantiation
Template argument deduction is used in explicit instantiations, explicit specializations, and those friend declarations where the declarator-id happens to refer to a specialization of a function template (for example, friend ostream& operator<< <> (...)), if not all template arguments are explicitly specified or defaulted, template argument deduction is used to determine which template's specialization is referred to.
P is the type of the function template that is being considered as a potential match, and A is the function type from the declaration. If there are no matches or more than one match (after partial ordering), the function declaration is ill-formed:
template<class X> void f(X a); // 1st template f
template<class X> void f(X* a); // 2nd template f
template<> void f<>(int* a) { } // explicit specialization of f
// P1 = void(X), A1 = void(int*): deduced X = int*, f<int*>(int*)
// P2 = void(X*), A2 = void(int*): deduced X = int, f<int>(int*)
// f<int*>(int*) and f<int>(int*) are then submitted to partial ordering
// which selects f<int>(int*) as the more specialized template

not getting expected ambiguity on template specialization and overloading c++

Consider
Class Wow{
public:
//main metod
template<typename T>
void foo(T t){
cout << t << endl;
}
template<>
void foo<int>(int t){
cout << "specialization" << endl;
}
void foo(int t){
cout << "overloading" << endl;
}
}
and the main is
Wow wow;
wow.foo(2.2);
wow.foo(1);
this outputs
2.2
overloading
My question is why does that even compile?
practically, foo is defined twice as void foo(int).
1) why does this pass?
2) why does the compiler choose the overloading one?
Thanks
1) Because there is no problem here. There is template function, function template specialization and overloading. You can call template specialization like this:
wow.foo<int>(3);
2) Overload has better match, than template specialization, if compiler can call this function with arg.
n4926 13.3.3/1.7
Given these definitions, a viable function F1 is defined to be a
better function than another viable function F2 if for all arguments
i, ICSi(F1) is not a worse conversion sequence than ICSi(F2) , and
then
F1 is not a function template specialization and F2 is a function
template specialization

C++ function template specialization declarations and template arguments; none vs. <> vs. <type>

When studying function templates, I see specializations declared in different ways:
template<> void f(argtype) {}
template<> void f<>(argtype) {}
template<> void f<argtype>(argtype) {}
... and I wonder about the differences between these. Given the below example with template functions with and without parameter, I have a few questions.
#include <iostream>
#include <typeinfo>
//Function print1 WITH function parameter---------------------------------------------
template<class T>
void print1(T) { std::cout << "Primary template for print1() with type " << typeid(T).name() << std::endl; }
template<>
void print1<int>(int) { std::cout << "Specialization for print1<int>(int)" << std::endl; }
//Not allowed, deduced to be the same as print1<int>(int)
/*template<>
void print1<>(int) { std::cout << "Specialization for print1<>(int)" << std::endl; }*/
//Not allowed, deduced to be the same as print1<int>(int)
/*template<>
void print1(int) { std::cout << "Specialization for print1(int)" << std::endl; }*/
//Function print2 WITHOUT function parameter------------------------------------------
/*Not allowed together with print<>(); compiler complains:
t2.cpp:29:6: error: template-id 'print2<>' for 'void print2()' does not match any template declaration*/
/*template<class T>
void print2() { std::cout << "Primary template for print2()" << std::endl; }*/
template<class T = short> //Declaration of print2<>() now ok in conjunction with print2<>()
void print2() { std::cout << "Primary template for print2()" << std::endl; }
template<>
void print2<int>() { std::cout << "Specialization for print2<int>()" << std::endl; }
template<>
void print2<>() { std::cout << "Specialization for print2<>()" << std::endl; }
int main() {
//These three work in the same way, no matter which call method we use, so far so good
print1(10);
print1<>(10);
print1<int>(10);
print1(true);
print1<>(true);
print1<bool>(true);
print2(); //Triggers print2<>(), a bit unexpectedly, should trigger print2<short>() (primary template)
print2<>(); //Triggers print2<>(), a bit unexpectedly, should trigger print2<short>() (primary template)
print2<bool>(); //Triggers print2<bool>() primary template
print2<short>(); //Triggers print2<>(), should definately trigger primary template for print2()
print2<int>(); //Triggers print2<int>() specialization
return 0;
}
outputs:
Specialization for print1<int>(int)
Specialization for print1<int>(int)
Specialization for print1<int>(int)
Primary template for print1() with type b
Primary template for print1() with type b
Primary template for print1() with type b
Specialization for print2<>()
Specialization for print2<>()
Primary template for print2()
Specialization for print2<>()
Specialization for print2<int>()
What special meaning is derived from leaving the template specialization argument empty, non-existent or with the specialized type and how does it effect the outcome?
It seems that with a function argument, this specification is superfluous and the compiler deduces it no matter how it's specified (with the result that equivalent explicit specifications become unallowed redeclarations).
I understand that given a function without parameters, the specialized template argument is needed explicitly in declaration to specify for which instantiation the defined function
applies to (since it can't be deduced otherwise). But the meaning seems to imply something more in this case and the "empty" specialization (<>) is triggered in a somewhat unforeseen ways. How come?
Why do I have to have a default template parameter when specializing print2 with print2<>() but not without it?
What special meaning is derived from leaving the template
specialization argument empty, non-existent or with the specialized
type and how does it effect the outcome?
If you do provide a template argument list completely then you're simply explicitly specializing the function template for a given set of template arguments.
If you provide arguments for a (possibly empty) subset of the template parameters then you are explicitly specializing the function template for a set of arguments that has to be deduced. According to [temp.deduct.decl]:
In a declaration whose declarator-id refers to a specialization of a
function template, template argument deduction is performed to
identify the specialization to which the declaration refers.
Specifically, this is done for explicit instantiations (14.7.2),
explicit specializations (14.7.3), and certain friend declarations
(14.5.4). […]. In all these cases, P is the type of the function
template being considered as a potential match and A is […] the
function type from the declaration […]. The deduction is done as
described in 14.8.2.5.
If, for the set of function templates so considered, there is either
no match or more than one match after partial ordering has been
considered (14.5.6.2), deduction fails and, in the declaration cases,
the program is ill-formed.
So for every parameter for which no argument was given, or in the case where no list is specified at all, template argument deduction is done for each corresponding parameter of the specialization and its counterpart from the primary template. The process is described in §14.8.2.5 and works just as if we called the primary template with the provided template argument list as the template arguments and objects of the types of the parameters in the specialization as the function arguments. You should be familiar with the fact that one can call a function template with some of the template arguments specified, e.g.
template <typename A, typename B> void foo(A, B);
foo(7684, 48.);
foo<int>(7684, 48.);
foo<int, double>(7684, 48.);
That works equivalently for explicit specializations:
template <typename T, typename U>
void foo(T, U) {}
// Both template arguments have to be deduced.
template<> void foo(double, float);
// The *exact* same as above.
// template<> void foo<>(double, float);
// Second template argument has to be deduced by type.
// If we call foo<int>(int(), float()) then the deduced specialization is
// foo<int, float>, thus U=float.
template<> void foo<int>(int, float);
template<> void foo<int, int>(int, int);
This can also be applied to overloads of a function template. In an attempt to find the primary template a specialization is corresponding to, the most specialized one is chosen.
template <typename T, typename U>
void foo(T&, U&) {}
template <typename T, typename U>
void foo(T const&, U&) {}
// Specializes the second overload because it is more specialized.
template <>
void foo(int const&, float&);
Note that while looking for a primary template, the arguments provided (i.e. not to be deduced) are used to check the resulting function parameter of the primary template against the resulting function parameter of the specialization. They have to be equal.
template <typename T, typename U>
void foo(T&, U&) {}
// Error - no matching primary template found.
template <>
void foo<int, int>(float&, int&);
// Dito:
template <>
void foo<int>(int, int&);
It seems that with a function argument, this specification is
superfluous and the compiler deduces it no matter how it's specified
(with the result that equivalent explicit specifications become
unallowed redeclarations).
Yes, that is indeed the case. Consider that if you specify a template argument invalidly that results in an error:
But the meaning seems to imply something more in this case and the
"empty" specialization (<>) is triggered in a somewhat unforeseen
ways. How come?
For a call, the template arguments are deduced first. Then the specialization with those template arguments is called.
If you explicitly specialized a function template for this particular specialization, here that is print2<> which is print2<short>, then that explicit specialization is thus called. In what way is that unforeseen?
Why do I have to have a default template parameter when specializing
print2 with print2<>() but not without it?
Because the compiler cannot deduce the argument. If you provide a default argument he doesn't have to deduce it in the first place.
What special meaning is derived from leaving the template specialization argument empty
Missing arguments are deduced if possible; an empty argument list means that all arguments are to be deduced.
non-existent
That means you're declaring the primary template, not an explicit specialisation.
or with the specialized type
That means you're declaring an explicit specialisation for that type.
the "empty" specialization (<>) is triggered in a somewhat unforeseen ways. How come?
In both cases, the template argument is deduced. In print1, the primary template declares that T is the same type as the function parameter; so it's deduced from the function parameter. In print2, it's declared with a default type of short, so that is used. So your surprise at seeing print2<> when you think it should be print2<short> is explained: print2<> is print2<short>.
Why do I have to have a default template parameter when specializing print2 with print2<>() but not without it?
If there were neither a default argument nor a function parameters from which to deduce an argument, then it would be impossible to deduce a type for the specialisation, so <> couldn't be used. I don't know what you mean by "without it"; if you mean "without <>", then you're declaring the primary template, not a specialisation, and the parameter is generic.

function template specialization failed?

#include <iostream>
template <class T>
void foo(T) {
std::cout << "foo(T)" << std::endl;
}
template <class T>
void foo(T*) { //#3
std::cout << "foo(T*)" << std::endl;
}
#define TEST
#ifdef TEST
template <>
void foo(int*) { //#1
std::cout << "foo(int*)" << std::endl;
}
#else
template <>
void foo<int*>(int*) { //#2
std::cout << "foo<int*>(int*)" << std::endl;
}
#endif
int main(int argc, char **argv) {
int* p = 0;
foo(p);
return 0;
}
What is the difference between #1 and #2 above? If I define TEST, then #1 works, but if I comment it out, #3 works. Which is the right way to write function template specialization here?
#1 declares a function template specialization of #3 and automatically deduces the template parameters. #2 is a specialization of the first template you defined (the one without number, let's call it #0) for T=int*. It can't be a specialization of #3 because replacing T with the specified int* there would lead to a int** parameter.
When you call foo, overload resolution now first picks the best fitting base template, then checks that template for any existing specializations. With TEST defined, there are two base templates (#0 and #3) and #3 is a better match and gets selected. Then the compiler checks for specializations of that template, and #1 is a better fit and is being called.
Without TEST defined, there are still two base templates (#0 and #3) and #3 is a better match and gets selected. Then the compiler checks for specializations of that template, but since #2 specializes #0 and not #3, it is not considered and #3 ends of being called.
This is the classical example of Why not Specialize Function Templates. The problems are explained in more detail there.
The simple solution is to not specialize function templates at all, but simply add new overloads for the special types:
// no template, just a normal function
void foo(int*) {
std::cout << "foo(int*)" << std::endl;
}
For function template specializations you can explicitly list the template arguments but you don't have to if the template arguments are deduced. If you don't specify the template arguments, they are deduced by the compiler using the same rules as overload resolution. For deciding which function overload is to be chosen, the compiler starts with looking only at the primary templates (which are selected by some magical process in the first place). Looking at the two available primary templates
template <typename T> void foo(T);
template <typename T> void foo(T*);
the latter is a better match for a pointer argument. Once the proper primary template is found, the compiler looks for potential specializations of this primary template. However, your example #2 actually is not a specialization of function template taking a pointer argument although it involves a pointer argument. If you take the primary declaration
template <typename T> void foo(T*);
and you replace T by the explicitly specified template argument int* you get
template <> void foo<int*>(int**);
That is, the declaration
template <> void foo<int*>(int*);
is something different. You probably just want to lose the pointer when specifying the template argument:
template <> void foo<int>(int*);
I can't really tell which function #2 is supposed to specialize, or exactly how the extremely complicated overload resolution rules would select the function to call.
I do know that you most often don't need to specialize functions, but can rely on overloading instead. To get a function for int* you just need
void foo(int*) {
std::cout << "foo(int*)" << std::endl;
}
A non-template function will be preferred over templates, as long as the parameter matches.