Petr Skocik
Petr Skocik

Reputation: 60058

Explicit template instantiation

I'm trying to compile with explicit template instatiation only.

Consider this dummy snippet

#include <vector>

template struct std::allocator<int>;
template struct std::vector<int, std::allocator<int>>;

void fun(){
  std::vector<int> v;
}

int main (){
  fun();
};

I would like to compile it with

g++ -std=c++11  -fno-implicit-templates fun.cc 

I expected this to work, however it complains of unresolved references to std::vector member functions. Shouldn't member functions be automatically instantiated along with the std::vector class? How can I make it work?

The compiler error is:

/tmp/cc1QxQUn.o: In function `std::vector<int, std::allocator<int> >::push_back(int const&)':
vec.cc:(.text._ZNSt6vectorIiSaIiEE9push_backERKi[_ZNSt6vectorIiSaIiEE9push_backERKi]+0x65): undefined reference to `void std::vector<int, std::allocator<int> >::_M_emplace_back_aux<int const&>(int const&)'
/tmp/cc1QxQUn.o: In function `std::vector<int, std::allocator<int> >::push_back(int&&)':
vec.cc:(.text._ZNSt6vectorIiSaIiEE9push_backEOi[_ZNSt6vectorIiSaIiEE9push_backEOi]+0x2a): undefined reference to `void std::vector<int, std::allocator<int> >::emplace_back<int>(int&&)'
/tmp/cc1QxQUn.o: In function `std::vector<int, std::allocator<int> >::insert(__gnu_cxx::__normal_iterator<int const*, std::vector<int, std::allocator<int> > >, int const&)':
vec.cc:(.text._ZNSt6vectorIiSaIiEE6insertEN9__gnu_cxx17__normal_iteratorIPKiS1_EERS4_[_ZNSt6vectorIiSaIiEE6insertEN9__gnu_cxx17__normal_iteratorIPKiS1_EERS4_]+0x14d): undefined reference to `void std::vector<int, std::allocator<int> >::_M_insert_aux<int>(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, int&&)'
vec.cc:(.text._ZNSt6vectorIiSaIiEE6insertEN9__gnu_cxx17__normal_iteratorIPKiS1_EERS4_[_ZNSt6vectorIiSaIiEE6insertEN9__gnu_cxx17__normal_iteratorIPKiS1_EERS4_]+0x166): undefined reference to `void std::vector<int, std::allocator<int> >::_M_insert_aux<int const&>(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, int const&)'
/tmp/cc1QxQUn.o: In function `std::vector<int, std::allocator<int> >::insert(__gnu_cxx::__normal_iterator<int const*, std::vector<int, std::allocator<int> > >, int&&)':
vec.cc:(.text._ZNSt6vectorIiSaIiEE6insertEN9__gnu_cxx17__normal_iteratorIPKiS1_EEOi[_ZNSt6vectorIiSaIiEE6insertEN9__gnu_cxx17__normal_iteratorIPKiS1_EEOi]+0x32): undefined reference to `__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > > std::vector<int, std::allocator<int> >::emplace<int>(__gnu_cxx::__normal_iterator<int const*, std::vector<int, std::allocator<int> > >, int&&)'
/tmp/cc1QxQUn.o: In function `void std::vector<int, std::allocator<int> >::_M_assign_dispatch<int const*>(int const*, int const*, std::__false_type)':
vec.cc:(.text._ZNSt6vectorIiSaIiEE18_M_assign_dispatchIPKiEEvT_S5_St12__false_type[_ZNSt6vectorIiSaIiEE18_M_assign_dispatchIPKiEEvT_S5_St12__false_type]+0x2d): undefined reference to `void std::vector<int, std::allocator<int> >::_M_assign_aux<int const*>(int const*, int const*, std::forward_iterator_tag)'
/tmp/cc1QxQUn.o: In function `void std::vector<int, std::allocator<int> >::_M_insert_dispatch<int const*>(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, int const*, int const*, std::__false_type)':
vec.cc:(.text._ZNSt6vectorIiSaIiEE18_M_insert_dispatchIPKiEEvN9__gnu_cxx17__normal_iteratorIPiS1_EET_S9_St12__false_type[_ZNSt6vectorIiSaIiEE18_M_insert_dispatchIPKiEEvN9__gnu_cxx17__normal_iteratorIPiS1_EET_S9_St12__false_type]+0x32): undefined reference to `void std::vector<int, std::allocator<int> >::_M_range_insert<int const*>(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, int const*, int const*, std::forward_iterator_tag)'
/tmp/cc1QxQUn.o: In function `void std::vector<int, std::allocator<int> >::_M_assign_dispatch<std::move_iterator<__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > > > >(std::move_iterator<__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > > >, std::move_iterator<__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > > >, std::__false_type)':
vec.cc:(.text._ZNSt6vectorIiSaIiEE18_M_assign_dispatchISt13move_iteratorIN9__gnu_cxx17__normal_iteratorIPiS1_EEEEEvT_S9_St12__false_type[_ZNSt6vectorIiSaIiEE18_M_assign_dispatchISt13move_iteratorIN9__gnu_cxx17__normal_iteratorIPiS1_EEEEEvT_S9_St12__false_type]+0x2d): undefined reference to `void std::vector<int, std::allocator<int> >::_M_assign_aux<std::move_iterator<__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > > > >(std::move_iterator<__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > > >, std::move_iterator<__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > > >, std::forward_iterator_tag)'
collect2: error: ld returned 1 exit status

Upvotes: 3

Views: 702

Answers (1)

Barry
Barry

Reputation: 302757

From [temp.explicit]:

An explicit instantiation that names a class template specialization is also an explicit instantiation of the same kind (declaration or definition) of each of its members (not including members inherited from base classes and members that are templates) that has not been previously explicitly specialized in the translation unit containing the explicit instantiation, except as described below.

So while you're explicitly instantiating std::vector<int>, you're not instantiating any of its member function templates - so you're getting undefined references for all of those (e.g. _M_emplace_back_aux is a function template). You'd have to add all of those explicitly:

template void std::vector<int>::_M_emplace_back_aux<int>(int&& );
template void std::vector<int>::_M_emplace_back_aux<const int&>(const int& );
template void std::vector<int>::_M_assign_aux<int const*>(int const*, int const*, std::forward_iterator_tag);
...

Or just - let implicit instantiation just do its thing.

Upvotes: 3

Related Questions