Why uncalled template class members *parameters* ARE instantiated? - c++

This question is a counterpoint to: Why uncalled template class members aren't instantiated?, where the author was surprised that some template methods weren't instantiated.
I have the opposite problem: parts of my function are getting instantiated when I don't expect them to. Take the following program:
template <class T> class Foo;
template <class T>
class Bar {
template <class U> void Baz(typename Foo<T>::X x) {}
};
int main() {
Bar<int> bar;
}
This program fails to compile with the error:
test.cc:6:40: error: implicit instantiation of undefined template 'Foo<int>'
template <class U> void Baz(typename Foo<T>::X x) {}
^
test.cc:10:12: note: in instantiation of template class 'Bar<int>' requested here
Bar<int> bar;
^
test.cc:2:26: note: template is declared here
template <class T> class Foo;
But why is it trying to instantiate a parameter of a function I haven't called? It's a template function with a template parameter that it cannot know, which makes it doubly weird that it instantiates the function argument type.
Why does it do this? And why does SFINAE not help me here, and at worst remove the overload from consideration?

When you create an instance of a template class, the class needs to be fully defined. This includes the member function declarations. If one of the member function declarations are not fully defined, then the class itself is not fully defined.
In this case, there's no definition for Foo<T>::X so the Baz function can not be fully declared, and the class as a whole is not fully defined.

Related

C++ partial specialization in source file

I have a problem concerning partial class template specialization in c++. I have one class A with two templates T,U. Then i want two class specializations with exclusive methods print_me(), only visible for those two specializations. Apart from that i need fully specialized member functions add_integer/add_double. When i implement those methods in the header file, it compiles fine. But id really like my implementations to be in the source file, which is no problem for the fully specialized functions, but for the partial ones. I get following errors for the code below:
test.h:27:25: error: declaration of ‘void A<int, U>::print_me()’ outside of class is not definition [-fpermissive]
test.h:30:28: error: declaration of ‘void A<double, U>::print_me()’ outside of class is not definition [-fpermissive]
But if i leave out the declarations of print_me() in the header file i get an undefined reference error, which i understand, as my compiler cant know, which methods to instantiate when compiling.
test.h:
//Primary Template Class
template <typename T, typename U>
class A{};
//Partial Specialization 1
template <typename U>
class A<int,U>
{
public:
void add_double(double a);
void print_me();
};
//Partial Specialization 2
template <typename U>
class A<double,U>
{
public:
void add_int(int a);
void print_me();
};
//explicit specialization
template <>
void A<int,double>::add_double(double a);
//explicit specialization
template <>
void A<double,int>::add_int(int a);
//partial specialization
template <typename U>
void A<int,U>::print_me();
//partial specialization
template <typename U>
void A<double,U>::print_me();
test.cpp
#include "test.h"
template <>
void A<int,double>::add_double(double a){}
template <>
void A<double,int>::add_int(int a){}
template <typename U>
void A<int,U>::print_me(){};
template <typename U>
void A<double,U>::print_me(){};
for testing purpose main.cpp
#include "test.h"
int main()
{
A<int,double> * a_0=new A<int,double>;
A<double,int> * a_1=new A<double,int>;
a_0->add_double(1.1);
a_0->print_me();
a_1->add_int(1);
a_1->print_me();
return 0;
}
So is there any possibility to have the print_me() methods implemented in the source file? Whats the difference between fully and partially specialized member functions in this context?
Any hints will be appreciated
as #Angew mentioned, partial specialization is still a template, which is just a blueprint for yourprint_memethod.
you need to instantiate your template function. for that you can use explicit instantiation or implicit instantiation in your test.cpp file.
Explicit Instantiation:
template
void A<double,int>::add_int(int a);
Implicit Instantiation:
just define a dummy function in test.cpp which will call the fully specialized template function print me (you don't have to use this dummy function) :
void instatiatePrintMe()
{
A<int, double> a;
a.print_me();
}
you can read here for more information: C++ - Defining class template (header/source file)

Why the common template method definition doesn't match the template class specialization?

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.

what does template<> (without any class T in the <>) mean?

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
};

Need help regarding Template class instantiation

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!

Difference between instantiation and specialization in c++ templates

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).