I'm reading some source code in stl_construct.h,
In most cases it has sth in the <>
and i see some lines with only "template<> ...".
what's this?
This would mean that what follows is a template specialization.
Guess, I completely misread the Q and answered something that was not being asked.
So here I answer the Q being asked:
It is an Explicit Specialization with an empty template argument list.
When you instantiate a template with a given set of template arguments the compiler generates a new definition based on those template arguments. But there is a facility to override this behavior of definition generation. Instead of compiler generating the definition We can specify the definition the compiler should use for a given set of template arguments. This is called explicit specialization.
The template<> prefix indicates that the following template declaration takes no template parameters.
Explicit specialization can be applied to:
Function or class template
Member function of a class template
Static data member of a class template
Member class of a class template
Member function template of a class template &
Member class template of a class template
It's a template specialization where all template parameters are fully specified, and there happens to be no parameters left in the <>.
For example:
template<class A, class B> // base template
struct Something
{
// do something here
};
template<class A> // specialize for B = int
struct Something<A, int>
{
// do something different here
};
template<> // specialize both parameters
struct Something<double, int>
{
// do something here too
};
Related
Let's say I have this code
template<typename T2, typename T = int>
struct X
{
static double f;
};
template<typename T>
double X<T>::f = 14.0;
If I try to compile clang give me the following error
nested name specifier 'X::' for declaration does not refer into a
class, class template or class template partial specialization
and for GCC :
error: template definition of non-template 'double X::f'
The question is :
Why the compiler want us to specialize the struct X like that :
template<typename T2>
struct X<T2,int>
{
static double f;
};
The first declaration has int as a default argument, why the compiler don't choose this declaration ?
I searched in the standard anchor [temp.spec] but it didn't help.
I ask this question after answered this one on SO.
Thanks for your help !
"Why the compiler want us to specialize the struct X like that" - that's not what the error messages are saying. You don't need to do this, and you really shouldn't do it unless what you want is a partial specialization and a static member defined only for that partial specialization.
The problem is that template<typename T2, typename T = int> struct X is a class template that has two template parameters. The fact that the second one has a default template argument doesn't change the fact that there are still two parameters.
So, you need to define your class template member as belonging to a class template with two parameters, like this:
template<typename T2, typename T>
double X<T2, T>::f = 14.0;
The relevant paragraphs in the standard (N4527, the current draft):
[14.5.1p3]
When a member function, a member class, a member enumeration, a static
data member or a member template of a class template is defined
outside of the class template definition, the member definition is
defined as a template definition in which the template-parameters are
those of the class template. The names of the template parameters used
in the definition of the member may be different from the template
parameter names used in the class template definition. The template
argument list following the class template name in the member
definition shall name the parameters in the same order as the one used
in the template parameter list of the member. Each template parameter
pack shall be expanded with an ellipsis in the template argument list.
[14.1p9]
[...] A default template-argument shall not be specified in the
template-parameter-lists of the definition of a member of a class
template that appears outside of the member’s class. [...]
As specified in the quote above, the actual names of the template parameters (T2 and T) don't matter, they can be different from the ones in the class template definition, but they need to be consistent within the definition of the member. That is, you can do this
template<typename T, typename U>
double X<T, U>::f = 14.0;
and it will still define the member of the correct X class template. However, using the same names can make things easier to understand when reading the code.
By defining the partial specialization before the definition of f in your original example, template<typename T> double X<T>::f = 14.0; becomes a valid definition of the member f of the partial specialization template<typename T2> struct X<T2,int>, and only of that template (partial specializations are templates themselves). The member f of the primary template template<typename, typename> struct X remains undefined.
The relevant wording is in [14.5.5.3p1]:
The template parameter list of a member of a class template partial
specialization shall match the template parameter list of the class
template partial specialization. The template argument list of a
member of a class template partial specialization shall match the
template argument list of the class template partial specialization. A
class template specialization is a distinct template. The members of
the class template partial specialization are unrelated to the members
of the primary template. [...]
I have the following code:
template <class T, class U = T>
class A {
public:
void f();
};
template <class T>
class A<T, T> {
public:
void f(); // Unaltered method.
// Some differences.
};
template <class T, class U>
void A<T, U>::f() {}
int main() {
A<int> a;
a.f();
return 0;
}
The clang++ -std=c++11 test.cc gives me an error: undefined reference to 'A<int, int>::f()'
Why the provided definition of method f() doesn't apply to the class A<int, int>?
The primary class template template <class T, class U = T> class A and the partial specialization template <class T> class A<T, T> are two distinct template definitions. After they've been defined, whenever you refer to the class template name A, the primary template and all partial specializations will always be considered.
Whenever you instantiate A with either a single template argument, or two arguments of the same type, it'll form a better match for the specialization you've provided, and the primary template is not considered.
In your example, because of the partial specialization you've provided, there's no way to match the primary template, regardless of the default template argument, if you try to instantiate A with a single template argument, or two of the same type.
The solution, of course, is to provide the definition for A<T, T>::f()
template <class T>
void A<T, T>::f() {}
EDIT:In the presence of partial specializations, the rules for matching them are given by (from N3797) §14.5.5.1/1 [temp.class.spec.match]
When a class template is used in a context that requires an
instantiation of the class, it is necessary to determine whether the
instantiation is to be generated using the primary template or one of
the partial specializations. This is done by matching the template
arguments of the class template specialization with the template
argument lists of the partial specializations.
— If exactly one matching specialization is found, the instantiation is generated from that specialization.
— If more than one matching specialization is found, the partial order rules (14.5.5.2) are used to determine whether one of the
specializations is more specialized than the others. ...
— If no matches are found, the instantiation is generated from the primary template.
In your example the first rule applies, and the compiler doesn't even get to the 3rd rule.
When you define a member function of a class template outside the class, you are just defining the function for the corresponding function that was declared in the class template. You are not creating a new function template which might match other parameters. In your example:
template <class T, class U = T>
class A {
public:
void f(); // This is the declaration of A<T,U>::f()
};
template <class T>
class A<T, T> {
public:
void f(); // This is the declaration of A<T,T>::f()
};
template <class T, class U>
void A<T, U>::f() {} // This is the definition of A<T,U>::f()
// There is no definition of A<T,T>::f()
I believe what you are thinking is that the compiler will see that you are calling A<int,int>::f() and will look through the member function definitions and find one that matches, but this is not what happens. The compiler always looks through the class templates to find which function to call, and once it has found a match, it then looks for the corresponding definition. In your case, you are calling A<int,int>::f(), so it first looks for a class definition that matches A<int,int> and it finds your A<T,T> class template specialization. It sees that A<T,T> does indeed have a member function called f which matches your function call, which means A<T,T>::f() needs to be instantiated. To instantiate A<T,T>::f(), the compiler looks for the definition of A<T,T>::f(), however it doesn't find it. It only finds the definition of A<T,U>::f, which isn't a match. The template parameter matching that is used to find a proper function declaration doesn't apply.
Let me present my problem with an example :
template <typename T> class a{
public:
T data;
a():data(T()){}
a(T temp): data(temp) {}
};
So if write in main() like
a(30);
a("String");
So according to the template argument deduction rule , it should be able to generate the first temporary class as a<int>(30) etc
But I the error which says:
missing template arguments before '(' token
so why this happens, this is only true for function template?
Template parameter deduction from arguments only works for functions, never for classes. Until you know the type of the class, i.e. all its template parameters, you don't even know which member functions the class has!
So, you always have to say the template parameters if you want to construct an object directly:
a<int> x(30);
Here's a little thought experiment to expand on the above. Suppose we have
template <typename T> class Foo;
and we are calling Foo::somefunction(x);, where x is some type. You think, well, I declared somefunction() like this:
template <typename T> class Foo
{
static void somefunction(const T & x);
};
so it should be obvious that T is the same type as the type of x. But now imagine I have a specialization:
template <> class Foo<char>
{
static void anotherfunction(double x);
};
The class Foo<char> doesn't even have a function somefunction(), so the expression Foo::somefunction(x) doesn't even get to the stage where I could look up the argument!
The usual way around this is to make a free helper function that constructs your object:
template <typename T> a<T> make_a(const T & x) { return a<T>(x); }
Since this is a function template, its parameters can be deduced:
make_a(30); // type a<int>
make_a("hello"); // type a<char[6]>
The constructor is not a template, its the class which is a template. So when you write a(30), the template argument deduction for the class template cannot be done!
If there exists a constructor template, then the template argument for the templated constructor can be deduced by the compiler. For example here:
template <typename T> class A{
public:
template<typename U>
A(const U &): {} //note : it's a constructor template
};
A<char> obj(30); //U is deduced as int
In the above example, only U can be deduced, you still have to provide T. Its because
U is a template argument for the constructor template. Template argument deduction can be done in this case.
T is a template argument for the class template. Template argument deduction cannot be done here.
You still need to declare a temporary as, for example, a<int>(30).
You cannot infer class template arguments from the arguments to the constructor- unfortunately.
Template type deduction only happens for template functions. You need to specify the parameters for a template class instantiation . You can use a function template to deduce the template parameter and return the appropriate type. In c++0 x you could use auto to hold the instance. Can't easily write example code for you on my phone!
template <typename T>
struct A
{
template <typename U>
struct B;
template <>
struct B<int> {static const int tag = 1;}; // Works fine in VS2010
};
How can I specialize B the same way, but outside of A. I tried this with no success :
template <typename T> template <>
struct A<T>::B<int> {static const int tag = 1;};
I get:
error C3212: 'A<T>::B<int>' : an explicit specialization of a template member must be a member of an explicit specialization
It does not make sense since I can do exactly that by defining it inside the class
VS2010 problem? Wrong syntax?
Thanks
PS: This one (which should be wrong anyway, crashes VS2010):
template <> template <typename T>
struct A<T>::B<int> {static const int tag = 1;};
To quote the C++ spec, §14.17.3.18:
In an explicit specialization declaration for a member of a class template or a member template that appears in namespace scope, the member template and some of its enclosing class templates may remain unspecialzed, except that the declaration shall not explicitly specialize a class member template if its enclosing class templates are not explicitly specialized as well. [...]
(my emphasis)
This suggests that you can't specialize a template class nested inside another template class unless the outer template class is specialized as well. So it looks like VS2010 has this behavior wrong and g++ has it right.
It just doesn't work that way.:-(
You cannot specialize a function inside the class declaration, even though msvc accepts this with its default settings.
You also cannot specialize a member function without also specializing the enclosing class. Most compilers avred on this (as does the language standard).
What is the difference between specialization and instantiation in context of C++ templates. From what I have read so far the following is what I have understood about specialization and instantiation.
template <typename T>
struct Struct
{
T x;
};
template<>
struct Struct <int> //specialization
{
//code
};
int main()
{
Struct <int> s; //specialized version comes into play
Struct <float> r; // Struct <float> is instantiated by the compiler as shown below
}
Instantiation of Struct <float> by the compiler
template <typename T=float>
struct Struct
{
float x;
}
Is my understanding of template instantiation and specialization correct?
(Implicit) Instantiation
This is what you refer to as instantiation (as mentioned in the Question)
Explicit Instantiation
This is when you tell the compiler to instantiate the template with given types, like this:
template Struct<char>; // used to control the PLACE where the template is inst-ed
(Explicit) Specialization
This is what you refer to as specialization (as mentioned in the Question)
Partial Specialization
This is when you give an alternative definition to a template for a subset of types, like this:
template<class T> class Struct<T*> {...} // partial specialization for pointers
What is the difference between specialization and instantiation in context of C++ templates?
Normally (no specializations present) the compiler will create instantiations of a template when they are used, by substituting actual template parameters (int in your example) for the formal template parameters (T) and then compile the resulting code.
If a specialization is present, then for the (set of) special template parameter(s) specified by that specialization, that specialization's implementation is to be used instead of what the compiler would create.
Overview
Specialization: The class, function or class member you get when substituting template arguments into the template parameters of a class template or function template.
Instantiation: The act of creating a specialization out of a template or class template member. The specialization can be created out of a partial specialization, class template member or out of a primary class or function template.
An explicit specialization is one that defines the class, function or member explicitly, without an instantiation.
A template specialization actually changes the behaviour of the template for a specific type. eg convert to a string:
template<typename T> std::string convertToString( const T& t )
{
std::ostringstream oss;
oss << t;
return oss.str();
}
Let's specialise that though when our type is already a std::string as it is pointless going through ostringstream
template<> std::string convertToString( const std::string & t )
{
return t;
}
You can specialise for classes too.
Now instantiation: this is done to allow you to move the compilation for certain types into one compilation unit. This can save you both compilation time and sometimes code-bloat too.
Let's say we make the above into a class called StringConvert rather than a function.
template<typename T>
class StringConvert
{
public:
// 4 static functions to convert from T to string, string to T,
// T to wstring and wstring to T using streams
};
We will convert a lot of integers to strings so we can instantiate it: Put this inside one header
extern template class StringConvert<int>;
Put this inside one compilation unit:
template class StringConvert<int>;
Note that the above can also be done (without the extern in the header) with functions that are actually not implemented inline. One of your compilation units will implement them. However then your template is limited only to instantiated types. Sometimes done when the template has a virtual destructor.
In c++ 11.
instantiation:
Instantiate the template with given template arguments
template <typename T>
struct test{ T m; };
template test<int>;//explicit instantiation
which result in a definition of a struct with a identifier test<int>
test<int> a;//implicit instantiation
if template <typename T> struct test has been instantiated with argument T = int before(explicit or implicit), then it's just a struct instantiation. Otherwise it will instantiate template <typename T> struct test with argument T = int first implicitly and then instantiate an instance of struct test<int>
specialization:
a specialization is still a template, you still need instantiation to get the real code.
template <typename T>
struct test{ T m; };
template <> struct test<int>{ int newM; } //specialization
The most useful of template specialization is probably that you can create different templates for different template arguments which means you can have different definitions of class or function for different template arguments.
template<> struct test<char>{ int cm; }//specialization for char
test<char> a;
a.cm = 1;
template<> struct test<long> { int lm; }//specialization for long
test<long> a;
a.lm = 1;
In addition to these full template specializations above, there(only class template) exits partial template specialization also.
template<typename T>
struct test {};
template <typename T> struct test<const T>{};//partial specialization for const T
template <typename A, typename B>
struct test {};
template <typename B> struct test<int, B>{};//partial specialization for A = int
A specialized template is no longer just a template. Instead, it is either an actual class or an actual function.
A specialization is from either an instantiation or an explicit specialization, cf 14.7.4 below.
An instantiation is based on a primary template definition. A sample implicit class template instantiation,
template<typename T>
class foo {}
foo<int> foo_int_object;
A sample explicit class template instantiation,
template class foo<double>;
An explicit specialization has a different definition from it's primary template.
template<>
class foo<bool> {}
// extract from standard
14 Templates
14.7 Template instantiation and specialization
4 An instantiated template specialization can be either implicitly instantiated (14.7.1) for a given argument
list or be explicitly instantiated (14.7.2). A specialization is a class, function, or class member that is either
instantiated or explicitly specialized (14.7.3).