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)
Related
I have a class A with template argument T, which is limited to two types: T1 and T2. Because of this, I explicitly instantiated class A for types T1 and T2 such that A's functionality can be defined in a source file and doesn't need to be recompiled every time A.hpp is included.
A.hpp:
template<typename T>
class A {
public:
void basicMethod();
};
template class A<T1>;
template class A<T2>;
A.cpp:
template<typename T>
void A<T>::basicMethod() {
// ...
}
However, now I want to add a templated method to both A<T1> and A<T2> where the template argument is limited to two types again: S1 and S2:
A.hpp:
template<typename T>
class A {
public:
void basicMethod();
template<typename S>
void advancedMethod();
};
template class A<T1>;
template class A<T2>;
// How to explicitly instantiate A::advancedMethod here?
A.cpp:
template<typename T>
void A<T>::basicMethod() {
// ...
}
template<typename T>
template<typename S>
void A<T>::advancedMethod() {
// ...
}
How do I explicitly instantiate A<T>::advancedMethod<S> for (T, S) = {T1, T2} x {S1, S2}? Based on what I found online, I tried adding things like this to the end of A.hpp:
template void A<T1>::advancedMethod(S1);
template void A<T1>::advancedMethod(S2);
template void A<T2>::advancedMethod(S1);
template void A<T2>::advancedMethod(S2);
However, this did not work at all.
Explicit instantiation definitions for member function templates of class templates
You nearly got it. The correct syntax is:
template void A<T1>::advancedMethod<S1>();
template void A<T1>::advancedMethod<S2>();
template void A<T2>::advancedMethod<S1>();
template void A<T2>::advancedMethod<S2>();
Specifically noting that advancedMethod() is a function template parameterized over a single type template parameter, with no function parameters: your explicit instantiation definitions for different specialization of the function template (for different specializations of the class template in which it is defined) should, like the explicit instantiation definitions for the class template, provide the template arguments (<...>) as to specify the specializations you wish to explicitly instantiate.
Finally, the advancedMethod() function template naturally needs to be defined (either via a primary template definition or in an explicit specialization) for each specialization which is explicitly instantiated; particularly (cppreference):
If a function template, variable template, member function template, or member function or static data member of a class template is explicitly instantiated with an explicit instantiation definition, the template definition must be present in the same translation unit.
Separating definitions of template functions (/class template member functions) from their declarations: the -timl.hpp pattern
As an effect of the requirement above, when supplying explicit instantiation definitions, you typically place these after the definitions of the related templated entities, in a source file, where the typical use case is that a user of the public API of the templated entity should not have access to the definitions (as in your example). This is essential as you may not explicitly instantiate the same specialization twice over different translation units, as per As per [temp.spec]/5:
For a given set of template arguments,
an explicit instantiation definition shall appear at most once in a program,
[...]
An implementation is not required to diagnose a violation of this rule.
Thus, if you place the explicit instantiations in the header, and then include the header in more than one source file, your program will be ill-formed, NDR.
// a.hpp
template<typename T>
class A {
public:
void basicMethod();
template<typename S>
void advancedMethod();
};
// a-timpl.hpp
#include "a.hpp"
template<typename T>
void A<T>::basicMethod() {
// ...
}
template<typename T>
template<typename S>
void A<T>::advancedMethod() {
// ...
}
// a.cpp
#include "a-timpl.hpp"
#include "t1.hpp"
#include "t2.hpp"
#include "s1.hpp"
#include "s2.hpp"
// Explicit instantiation definitions for
// production intent.
template class A<T1>;
template class A<T2>;
template void A<T1>::advancedMethod<S1>();
template void A<T1>::advancedMethod<S2>();
template void A<T2>::advancedMethod<S1>();
template void A<T2>::advancedMethod<S2>();
For test, you similarly include the -timpl.hpp header file rather than the main header (the main header is for the public API exposure), such that you may use the templated definitions to explicit instantiate specializations used in test:
// a_test.cpp
#include "a-timpl.hpp"
#include "t1_mock.h"
#include "t2_mock.h"
#include "s1_mock.h"
#include "s2_mock.h"
// Explicit instantiation definitions for
// test intent.
template class A<T1Mock>;
template class A<T2Mock>;
template void A<T1Mock>::advancedMethod<S1Mock>();
template void A<T1Mock>::advancedMethod<S2Mock>();
template void A<T2Mock>::advancedMethod<S1Mock>();
template void A<T2Mock>::advancedMethod<S2Mock>();
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.
How can I instantiate a variadic member function template of a class template in separate .cpp file? Say, given an above class template in a set of files: a.hpp with definition of interface, a_impl.hpp with implementation and a.cpp with instantiation, - which includes each previous in the chain sequentially, but only the first is visible to the user of the class (as opposed to the developer).
Especially interested in case of an empty parameter pack.
template <class A>
struct AA
{
template<class Z, class... Q>
void aa(double, Q... q) {};
};
template void AA<int>::aa<char>(double);
template void AA<int>::aa<char, char*>(double, char*);
template void AA<int>::aa<char, char*, char**>(double, char*, char**);
Note that in your setup only the "developer" can instantiate (one needs to see the implementation in order to be able to instantiate).
I am in need of your help once again...
I had the following code, which was causing explicit specialization in non-namespace scope error:
namespace __test
{
template <int A, int B, typename C> class Test
{
template <int V> void check(C & a) { }
template <> void check<0>(C & a) { } //error: explicit specialization in non-namespace scope 'class __test::Test<A, B, C>'
};
}
Since I already know how to fix this kind of errors, I defined specialization outside of the class scope, however I got another error - ... used without template parameters:
namespace __test
{
template <> void Test::check<0>(C & a) { } //error: 'template<int A, int B, class C> class __test::Test' used without template parameters
}
I'm probably just being stupid, but I don't understand the cause of this problem and I don't know how to fix it... Please help!
By my reading of the standard, what you want to do appears to be legal. Quoting §14.7.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 unspecialized, except that the declaration shall not explicitly specialize a class member template if its enclosing class templates are not explicitly specialized as well. In such explicit specialization declaration, the keyword template followed by a template-parameter-list shall be provided instead of the template<> preceding the explicit specialization declaration of the member. The types of the template-parameters in the template-parameter-list shall be the same as those specified in the primary template definition.
As you're explicitly specializing a member function template rather than a class member template, it should be fine; however, neither Comeau, GCC, nor VC++ allow the following, which should be correct syntax:
namespace test
{
template<int A, int B, typename C>
class Test
{
template<int V>
void check(C& a) { }
};
template<int A, int B, typename C>
template<>
void Test<A, B, C>::check<0>(C& a) { }
}
Comeau says error: a template declaration containing a template parameter list may not be followed by an explicit specialization declaration, which makes sense if we apply the rule in §14.7.3/18 to member function templates as well
GCC says invalid explicit specialization before '>' token; enclosing class templates are not explicitly specialized, which again makes sense if we apply the rule in §14.7.3/18 to member function templates as well
VC++ says error C2768: 'test::Test<A,B,C>::check' : illegal use of explicit template arguments, which isn't a helpful error message, but generally falls in line with the others
My guess is that there must be a defect report filed that also disallows explicit specializations of member function templates when the enclosing class templates are not explicitly specialized as well; however, I can't say this definitively since the wording for §14.7.3/18 hasn't changed between the C++03 standard and the C++0x FDIS (which it would if a DR was filed against C++03 and accepted).
You need to either fully specialize everything, like this:
namespace __test {
template <int A, int B, typename C>
class Test
{
template <int V> void check(C & a) { }
};
template <>
template <>
void Test<1, 2, int>::check<0> (int &)
{
}
}
Or use a helper structure to avoid trying to partially specialize template method of a template class (which GCC and many others won't understand):
namespace __test {
template <typename C, int V>
struct TestHelper
{
static void check (C & a)
{
}
};
template <typename C>
struct TestHelper<C, 0>
{
static void check (C & a)
{
}
};
template <int A, int B, typename C>
class Test
{
template <int V> void check(C & a)
{
TestHelper<C, V>::check (a);
}
};
}
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).