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>();
Related
So I've got a class that wants to instantiated for exactly one of two classes. I declare it in the header:
template <class T>
class MyClass {
public:
bool DoSomethingGeneric();
bool DoSomethingTSpecific();
};
Since I don't want to place the method definitions in the header, I instead place them in the implementation file, and perform an explicit specialization. While the DoSomethingGeneric method can be defined generically using a template, the DoSomethingTSpecific requires two separate implementations, one for each of the two possible classes for which I want to instantiate MyClass:
template <class T>
bool MyClass<T>::DoSomethingGeneric() {
// Generic code
}
template <>
bool MyClass<ClassA>::DoSomethingTSpecific() {
// ClassA-specific implementation
}
template <>
bool MyClass<ClassB>::DoSomethingTSpecific() {
// ClassB-specific implementation
}
Now, riddle me this: where do I place the explicit specialization? If I place it after my template definitions (like I usually do with specializations of purely-generic classes), clang says:
explicit specialization of 'MyClass<ClassA>' after instantiation
This message is accompanied by a pointer to the line where DoSomethingTSpecific is defined. This makes sense. My understanding is that the explicit specialization of the DoSomethingTSpecific method counts as an implicit specialization.
Meanwhile, if I place the specializations after all the template definitions, I see:
no function template matches function template specialization 'DoSomethingTSpecific'
This one is kind of a mystery to me.
Any thoughts? How can I have an explicit class-level specialization and explicit method specialization?
From the C++ Standard §14.7.3(5) Explicit specialization (emphasis mine):
Members of an explicitly specialized class template are
defined in the same manner as members of normal classes, and not using the template<> syntax.
Example:
template <> // specialization for classA
class MyClass<ClassA> {
public:
bool DoSomethingTSpecific(); // must be declared here
};
// template<> is not used here
bool MyClass<ClassA>::DoSomethingTSpecific() {
// ClassA-specific implementation
}
Demo:
http://cpp.sh/3tc2g
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)
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.
Is it possible to explicit instantiate one or more specializations of a template function?
Second, does it matter if the function is a class member?
Is it legal C++11 and also is it accepted by compilers so it doesn't come with problems?
Is it possible to explicit instantiate one or more specializations of a template function?
Yes, however,
[temp.explicit]/5:
For a given set of template arguments, if an explicit instantiation of a template appears after a declaration of an explicit specialization for that template, the explicit instantiation has no effect.
Second, does it matter if the function is a class member?
No, AFAIK;
[temp.explicit]/1:
A class, a function or member template specialization can be explicitly instantiated from its template. A member function, member class or static data member of a class template can be explicitly instantiated from the member definition associated with its class template. An explicit instantiation of a function template or member function of a class template shall not use the inline or constexpr specifiers.
Example from [temp.explicit]/3:
template<class T> class Array { void mf(); };
template class Array<char>;
template void Array<int>::mf();
template<class T> void sort(Array<T>& v) { /∗ ... ∗/ }
template void sort(Array<char>&); // argument is deduced here
namespace N {
template<class T> void f(T&) { }
}
template void N::f<int>(int&);
Is it legal C++11 and also is it accepted by compilers so it doesn't come with problems?
Well, yes, but for libraries there's always the problem of ABI compatibility; especially if different compilers have been used for library and library user (e.g. program including that library). The C++ Standard does not specify an ABI.
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).