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>();