Question

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
Was it helpful?

Solution

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.

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top