Say I declare a template class A
in a.h
#include <iostream>
template<bool b>
class A {
public:
void print(std::ostream& out);
};
And define the print method in a.cpp
(with explicit instatiation for true
and false
)
#include "a.h"
template<bool b>
void A<b>::print(std::ostream& out) {
out << "A" << b;
}
template class A<true>;
template class A<false>;
An example main main program in main.cpp
could be
#include "a.h"
int main() {
A<true> a;
a.print(std::cout);
}
The small project above compiles just fine.
Question: If I put the explicit instantiations above the definition of the print
method (in a.cpp
), the code doesn't compile anymore, with the usual undefined reference to A<true>::print(...)
error.
#include "a.h"
template class A<true>;
template class A<false>;
template<bool b>
void A<b>::print(std::ostream& out) {
out << "A" << b;
}
Why is this the case?
Edit: Makefile to compile
main : main.o a.o
g++ main.o a.o -o main
main.o : main.cpp
g++ -c main.cpp
a.o : a.cpp
g++ -c a.cpp
Whenever a template specialization is referenced in a context that requires instantiation, that context gives birth to a "point of instantiation" (which effectively denotes a location where the compiler is allowed to generate code for the referenced template specialization).
The act of creating a new definition of a function, class, or member of a class from a template declaration and one or more template arguments is called template instantiation.
To instantiate a template function explicitly, follow the template keyword by a declaration (not definition) for the function, with the function identifier followed by the template arguments. template float twice<float>(float original); Template arguments may be omitted when the compiler can infer them.
Implicit instantiation means that the compiler automatically generates the concrete function or class for the provided template arguments. In general, the compiler also deduces the template arguments from the function's arguments. In C++17, the compiler can also deduce the template arguments for class templates.
I don't think there is a good natural explanation for why this is so. Clearly, the compiler could see the definition of the member function even if it is provided after the explicit instantiation – because it is located in the same file.
However, compilers are not required to this; it is in fact explicitly forbidden by the Standard:
(§14.7.2/9) An explicit instantiation definition that names a class template specialization explicitly instantiates the class template specialization and is an explicit instantiation definition of only those members that have been defined at the point of instantiation.
I guess the reasons for this include the following:
There could be several distinct explicit specializations for some of the member functions later in the translation unit; it makes sense, also in the programmer's interest, to have an explicit rule about which of these will be instantiated;
When a template is implicitly instantiated, only specializations defined before the point of instantiation are taken into account; so the rule is the same for implicit and explicit instantiations.
template class A<true>;
template class A<false>;
The same reason why it is typically expected that template code is defined in the header itself. To perform explicit instantiation, you (the compiler) need to be able to see the entire definition of the template class, which isn't possible from your main.cpp
.
However a.cpp
has access to all of the definition of the class (here the print method) so explicit instantiation works there.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With