Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does position of explicit template instantiation matter

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
like image 442
Dejan Jovanović Avatar asked Jan 04 '13 06:01

Dejan Jovanović


People also ask

What is the point of instantiation?

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).

What is the instantiation of the class template?

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.

How do you instantiate a template in a function?

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.

What is implicit instantiation?

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.


2 Answers

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.

like image 85
jogojapan Avatar answered Sep 20 '22 11:09

jogojapan


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.

like image 24
Karthik T Avatar answered Sep 22 '22 11:09

Karthik T