Home > Net >  Why does 'extern template class' technique not work as expected?
Why does 'extern template class' technique not work as expected?

Time:11-16

The original question has been refined.

Given a source code file named main.cpp as follows:

#include <string>
extern template class std::basic_string<char>;

template<typename T>
struct A
{
    T n = {};

    T get() const
    {
        return n;
    }
};

extern template struct A<int>;

int main()
{
    auto a = A<int>{}.get(); // undefined reference to `A<int>::get() const'
    auto b = static_cast<int>(std::string{}.size()); // ok

    return a   b;
}

What I expected:

Note that the source code has extern template class std::basic_string<char> but no template class std::basic_string<char>.

So, the compiler would not instantiate class std::basic_string<char>, then g main.cpp would cause link errors on line std::string{}.size() as on line A<int>{}.get().

What I observed:

It is ok to g main.cpp on line std::string{}.size(). Online demo

Why does extern template class technique not work as expected?

CodePudding user response:

There are at least two reasons why it doesn't work.

One There is no prohibition against library class and function template instantiations being declared as extern template by the implementation. gcc and libstdc do just that.

$ g   -E main.cpp | grep 'extern.*string'
extern template class basic_string<char>;      // <-- from the library
extern template class basic_string<wchar_t>;   // <-- from the library
extern template class std::basic_string<char>; // <-- your line

The standard library implementation contains the explicit instantiation definitions (you can dig the source).

Two An entity that is the subject of an explicit instantiation declaration and that is also used in a way that would otherwise cause an implicit instantiation in the translation unit shall be the subject of an explicit instantiation definition somewhere in the program; otherwise the program is ill-formed, no diagnostic required [temp.explicit].

A possible rationale for the NDR is that extern template should not prevent inlining and other uses that do not involve linking. Indeed, with -O2 A::get is inlined, and the program builds just fine. There is no established technology that would force this program to be rejected no matter what. It can be rejected because of linker errors, but there is no requirement for linker errors to appear.

  • Related