Here is a code from the article Why not specialize function templates?
template<class T>
void f(T); // (1)
template<class T>
void f(T*); // (2)
template<>
void f<>(int*); // (3)
My question is about the last declaration. What does that syntax mean? When we want to fully specialize a function template, e.g. (1), for some type we usually write:
template<>
void f<int>(int);
i.e. we put that type into the angle-brackets after the function' name.
So what does the syntax (3) means?
In your case,
template<> void f<>(int*);
is an explicit specialization of
template<class T> void f(T*);
base template. It's the same as
template<> void f<int>(int*);
just the template argument is deduced.
You can even write:
template<> void f(int*);
with the same effect. A similar case is presented on cppreference, see section Explicit specializations of function templates, where there is written:
When specializing a function template, its template arguments can be omitted if template argument deduction can provide them from the function arguments.
The relevant part of the C++ Standard: http://eel.is/c++draft/temp.expl.spec#11.
A missing template argument will be deduced by the compiler if you don't provide it. In this particular case it will be deduced to int* because the second template is more specialized (but both are the candidates). So
template<> void f<>(int*)
will become
template<> void f<int>(int*)
after type deduction.
Related
In the current C++ standard draft, there is this example in this paragraph belonging to the section related to explicit specialization of templates:
template<class T> struct A {
void f(T);
template<class X1> void g1(T, X1);
template<class X2> void g2(T, X2);
void h(T) { }
};
// specialization
template<> void A<int>::f(int);
// out of class member template definition
template<class T> template<class X1> void A<T>::g1(T, X1) { }
// member template specialization
template<> template<class X1> void A<int>::g1(int, X1); //(1)
// member template specialization
template<> template<>
void A<int>::g1(int, char); //(2)
In (1) it seems more like g1 was specialized to be still a function template in the specialized version of A (A< int >), while in (2) it seems like g1 is itself specialized for its own set template parameters ( (int, from A< int >), char).
I find there to be a difference between these specializations (again, (1) feels like declaring a new version of g1 to be used for a "special version" of its "container" A, while (2) feels like a specialization regarding g1 itself (or regarding its own template parameters).
Furthermore, consider this example:
template<class T> struct A{
int f() { return 1; }
}
template<>
int A<int>::f() { return 2; } //(3)
To me (1) and (3) are the same "kind of specialization", one that is linked to a special version of the "container", while (2) is a specialization of the entity (template) itself.
Does the standard mention this difference or are these two kinds of specialization referred to as the same?
Thank you.
First, your #3 is equivalent to the first specialization in the cited example, except that the standard’s f uses the class’s template parameter in its signature—presumably to illustrate that, since the signature must match for a specialization, template arguments for the class may need to be repeated in the specialization declaration.
Then, the difference is that #1 is a specialization of a member of A<T> when T is int—a sort of shorthand for writing a specialization of A<int> itself that is mostly the same as the primary template. In particular, to avoid being misleading, the signature for the member being specialized must be unchanged from the (instantiation of the) primary template. In this case, that means it’s still a template.
On the other hand, #2 is a specialization of a template that happens to be a member of A<int>—the specialization is of A<int>::g1 itself, not of “A<T>::g1 when T is int” as for #1. This of course applies only when the member is a template, unlike #3. (In this case, #2 is a specialization of the very template declared by #1!)
Part of the point of [temp.expl.spec]/15 is that these two cases are not strongly distinguished syntactically. The difference is largely academic: both are surgical changes to a templated entity for certain arguments.
In C++, Explicit specializations of function templates is like:
template<typename T> return_type fun_name();
template<> return_type fun_name<int>(){/* blabla */}
The <int> in the above example is called template argument. Sometimes <int> can be ommitted because compiler can do Template Argument Deduction
But I can't find out why Template Argument Deduction failed in the following example:
//-------------failed case-------------
template <typename T>
struct deduce{
typedef T* type;
};
template <typename T>
typename deduce<T>::type fun1();
template <>
typename deduce<float>::type fun1<float>() //error if no "<float>" after fun1
{
}
//------------now the "Template Argument Deduction" works------------
template <typename T>
struct some_struct{
T* p;
};
template <typename T>
some_struct<T> fun2();
template <>
some_struct<float> fun2() // no error even if no "<float>" after fun2
{
}
If no <float> is after fun1, The error message is:
error: template-id ‘fun1<>’ for ‘float* fun1()’ does not match any template declaration
Maybe the compiler think the type(deduce<float>::type) marked by typename is less reliable than normal types ?
Let me provide an example of why non-deduced contexts are non-deduced. Template deduction is basically trying to match on the input. If I had:
template <class T> void foo(T );
and I call foo(4), that's easy. T=int. If I call foo('x'), T=char. These are easy substitutions to make. If T is nested somewhere in the type, like:
template <class T> void bar(std::vector<T> );
that's still totally doable. If I call it with a std::vector<std::vector<float>>, T=std::vector<float>. Still no problem.
Now consider this one:
template <class T> void baz(typename X<T>::type );
baz(4);
What's T? In all our previous cases, there was one obvious choice for T that was deduced directly from the argument passed to the function template. But here, that's not the case. We have an extra layer of indirection - we need to deduce a T to make a type X<T> whose member typedef type is int. How do we find such a thing?
Now let's say we had this:
template <class T> struct X { using type = T; };
Ok now it's easy right? T=int? Well, not so fast. For the primary template, that would work in this case. But what if there was also this specialization:
template <class T> struct X<T*> { using type = T; };
(that is, X is std::remove_pointer). Now we're in a situation where T=int works... but T=int* also works. And maybe there's some other type out there that also works for int. How do you pick the right one?
This problem - picking a template parameter in the nested-name specifier of qualified-id - is really hard and has no obvious path forward. So the compiler just won't take a path forward. It's a non-deduced context. T will never be deduced in the call to baz, the caller has to provide it:
baz<int>(4); // ahhhhh, ok, you wanted X<int>::type
Back to your question. some_struct<T> is a deduced-context, but typename deduce<T>::type is a non-deduced context. I hope it's clear now why the former works but the latter doesn't.
Maybe the compiler think the type(deduce<float>::type) marked by typename is less reliable than normal types ?
It has nothing to do with typename, the point is that deduce<T>::... is a nested-name-specifier; which belongs to Non-deduced contexts:
(emphasis mine)
In the following cases, the types, templates, and non-type values that are used to compose P do not participate in template argument deduction, but instead use the template arguments that were either deduced elsewhere or explicitly specified. If a template parameter is used only in non-deduced contexts and is not explicitly specified, template argument deduction fails.
1) The nested-name-specifier (everything to the left of the scope resolution operator ::) of a type that was specified using a qualified-id:
So, for
template <>
typename deduce<float>::type fun1()
deduce<float>::type (i.e. float*) will be used to deduce type T for deduce<T>::type, but T won't be deduced, template argument deduction fails. You have to explicitly specify it as float.
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.
I have a base template:
template <class X> void f(X x) {}
Now I have seen two ways to specialize it:
template <> void f<>(int x) {}
Or:
template <> void f<int>(int x) {}
gcc eats both variants, but not both at the same time.
Are these two specializations the same? When do I need to specify type in the second <> when specializing a template?
Both of your variants perform the same specialization. You can also use a third variant
template <> void f(int x) {}
which will also specialize the function template for X = int. It is equivalent to your second variant.
Variants with f<> and plain f rely on template argument deduction, while the f<int> variant specifies the template argument explicitly.
You might need to specify the type in <> explicitly when template argument deduction is impossible. In other cases you don't have to do it.
For example, if your function argument list did not depend on the template parameter X, then you'd have no choice but to specify the template argument explicitly
template <typename X> void bar() {}
template <> void bar<int>() {}
The above compiles. But if you replace the specialization with
template <> void bar<>() {}
it will fail to compile because the compiler cannot deduce the template argument.
The two specializations are the same. template<> always specializes an existing template, rather than declaring a new signature. If deduction from the specialization parameter types can determine what goes inside <>, then you are allowed to omit that part. (Leaving such things out may be a bad idea if there are more template overloads. It could become unclear which template is being specialized.)
By the way, specializing functions is usually a bad idea. Overload resolution will prefer a non-template overload and effectively hide the specialization you wish to prevent. Rather than combining the overloading and specialization mechanisms, just stick to overloading.
I am looking at some c++ code and do not understand the purpose of the template declaration in this situation:
template<> void operator>>(const ClassA& s, const ClassB d) {...}
What is the semantic of template<>?
This is, indeed, template specialization, as others before mentioned. There must be some previously declared function template, such as:
template<typename T, typename U>
void operator>>(const T& s, const U d) {...}
However, it is quite misguided. It is much better to remove the template<> altogether, so operator>> would just be overloaded. The problem with function template specialization is that it may lead to unexpected behaviour in the presence of overloaded functions (and operator>> has lots of overloads), since the specialization does not overload. This means that the compiler first selects the most appropriate overload for the function and then, if the selected overload is a function template, it looks for template specializations to see if there is an appropriate one.
A classical example (unfortunately, I don't remember where I read it). Consider this overloaded function template:
template <typename T>
void Function(T param);
template <typename T>
void Function(T* param);
template <>
void Function(int* param);
main()
{
int i = 5;
Function(&i);
}
As expected, the template specialization for int* is called. But just change the order of the function definitions:
template <typename T>
void Function(T param);
template <>
void Function(int* param);
template <typename T>
void Function(T* param);
main()
{
int i = 5;
Function(&i);
}
Now the general template for T* is called, since we are specializing the template for T, not for T*, and this second template is better suited for our call. This would be avoided if we overloaded the function instead of specializing the template:
void Function(int* param);
Now the order of declaration does not matter, we will always call the overload for int*.
UPDATE: Now I know who to credit. I read about this in an article by Herb Sutter. The example was provided by Peter Dimov and Dave Abrahams.
This is Template specialization
You use this syntax when you want to provide a special handler for a particular template type. Consider:
// A normal template definition.
template <typename AType>
whoami () { std::cout << "I am an unknown type."; }
// Now we specialize.
template <>
whoami<int> () { std::cout << "I am an integer!"; }
There's some other nonsense involved, particularly "partial specialization", but that's the basic function of template <>.
It is a template specialization: (fully or partially) resolving the template for a specific type. (Your particular example seems to be a full specialization, as no more template parameters are left unresolved in it. If the template has multiple parameters, and you specialize only some of them, it is called partial template specialization)
This allows one to provide type-specific optimizations for a given template, or to do many clever tricks such as detecting the static type of variables etc.