Kolja
Kolja

Reputation: 1247

Undefined symbols with extern templates in a static library

As far as I know the new extern template functionality exists to speed up compile and link times. I am trying to use this in a (static) library, which as far as I know should work, since Bjarne Stroustrup's C++11 FAQ explicitly mentions libraries.

What I have is a header file containing something along the lines of

template <typename T>
class Foo {
  // Definitions of the methods
};

extern template class Foo<int>;

And an implementation file

#include "Foo.hpp"
template class Foo<int>;

These are used to build a static library libfoo, which is then linked to the corresponding unit test FooTest. The linking then gives me undefined symbol errors for every method called on Foo objects in the test.

What am I doing/getting wrong here?

Upvotes: 2

Views: 665

Answers (1)

Jonathan Wakely
Jonathan Wakely

Reputation: 171263

Using your github code I can reproduce it with GCC 5.0 or Clang 3.4 but not Clang 3.6 (built from svn).

When it fails Foo.cpp.o does not contain a definition of qux::Foo<int, 2ul>::Foo(int const&)

$ nm -C Foo.cpp.o 
                 U qux::Foo<int, 2ul>::Foo(int const&)
0000000000000000 W qux::Foo<int, 2ul>::Foo()
                 U qux::Foo<int, 2ul>::Foo(int const&)
0000000000000000 W qux::Foo<int, 2ul>::Foo()
0000000000000000 W qux::Foo<int, 2ul>::operator[](unsigned long) const
0000000000000000 W std::array<int, 2ul>::operator[](unsigned long) const
0000000000000000 W std::__array_traits<int, 2ul>::_S_ref(int const (&) [2], unsigned long)

But using Clang 3.6 that symbol is defined in

$ nm -C Foo.cpp.o 
0000000000000000 W qux::Foo<int, 2ul>::Foo(int const&)
0000000000000000 W qux::Foo<int, 2ul>::Foo()
0000000000000000 W qux::Foo<int, 2ul>::Foo(int const&)
0000000000000000 W qux::Foo<int, 2ul>::Foo()
0000000000000000 n qux::Foo<int, 2ul>::Foo(int const&)
0000000000000000 n qux::Foo<int, 2ul>::Foo()
0000000000000000 W qux::Foo<int, 2ul>::operator[](unsigned long) const
0000000000000000 W std::array<int, 2ul>::operator[](unsigned long) const
0000000000000000 W std::__array_traits<int, 2ul>::_S_ref(int const (&) [2], unsigned long)
0000000000000000 W std::array<int, 2ul>::end()
0000000000000000 W std::array<int, 2ul>::data()
0000000000000000 W std::array<int, 2ul>::begin()
0000000000000000 W int* std::__addressof<int>(int&)

I'm not sure what the problem is, it might be a bug in Clang which has now been fixed, but it's strange that GCC has the same bug.

The function that causes the problem uses C++14's relaxed constexpr rules (looping in a constexpr function), so I assume it's a bug in the compilers' implementation of that new feature.

Upvotes: 6

Related Questions