'Exporting class template with out-of-body definitions from DLL with MinGW-w64
I am facing trouble properly linking a trivial Windows executable to a trivial DLL with MinGW-w64 (based on GCC 11.3.0 from MSYS2) when class templates are involved. A minimal reproducer is as follows.
The complete code of the library (library.cpp) is
template <class T> class __attribute__((dllexport)) TestClass
{
    public:
        void member() { __builtin_printf("member from library\n"); }
        void other_member();
};
template class __attribute__((dllexport)) TestClass<int>;
template <class T> void __attribute__((dllexport)) TestClass<T>::other_member () {}
and I compile it using
g++ -std=c++11 library.cpp -o library.dll -shared -Wl,--out-implib,library.dll.a -Wl,--output-def,library.def
The complete code of the program (program.cpp) is
template <class T> class __attribute__((dllimport)) TestClass
{
    public:
        void member() { __builtin_printf("member from program\n"); }
        void other_member();
};
extern template class __attribute__((dllimport)) TestClass<int>;
int main (void)
{
    TestClass<int> test;
    test.member();
    return 0;
}
and I compile it using
g++ -std=c++11 program.cpp library.dll.a -o program.exe
The linking of the program to the DLL fails with undefined reference to TestClass<int>::member(). It turns out that the linking failure can be solved in two ways:
- The extern template statement in the program is commented out. Then the compiler uses the local version of the template and the program prints "member from program".
 - The definition of 
TestClass<T>::other_memberis commented out from the library. Then the program properly links to theTestClass<int>::memberin the library and it prints "member from library". 
I understand the first point, where the extern template is avoided and a local implicit instantiation takes place. This also happens when I compile the code with optimizations.
But the second point perplexes me. Why does the out-of-body definition of TestClass<T>::other_member break export of TestClass<T>::member?
Disclaimer: I am debugging someone else's program, so the design choices are not mine.
Solution 1:[1]
Template classes are usually used in header files. They are merely definitions, which only become actual code once instantiated with an actual type.
So in that respect I don't see how this can be exported as a symbol in a DLL:
template <class T> class __attribute__((dllexport)) TestClass
This does make sense, since the compiler can generate code because the type is known:
template class __attribute__((dllexport)) TestClass<int>;
Here is how it would make more sense in my opinion:
library.hpp
#if !defined(DLL_EXPORT_LIBRARY)
# if defined(_WIN32) && defined(BUILD_LIBRARY_DLL)
#  define DLL_EXPORT_LIBRARY __declspec(dllexport)
# elif !defined(STATIC) && !defined(BUILD_LIBRARY_STATIC)
#  define DLL_EXPORT_LIBRARY __declspec(dllimport)
# else
#  define DLL_EXPORT_LIBRARY
# endif
#endif
template <class T> class TestClass
{
    public:
        void member();
        void other_member();
};
template class DLL_EXPORT_LIBRARY TestClass<int>;
template <class T> void __attribute__((dllexport)) TestClass<T>::other_member () {}
library.cpp
#include <library.hpp>
template <class T> void TestClass<T>::member()
{
    __builtin_printf("member from library\n");
}
program.cpp
#include <library.hpp>
int main (void)
{
    TestClass<int> test;
    test.member();
    return 0;
}
build:
g++ -std=c++11 library.cpp -I. -DBUILD_LIBRARY_DLL -o library.dll -shared -Wl,--out-implib,library.dll.a -Wl,--output-def,library.def
g++ -std=c++11 program.cpp -I. library.dll.a -o program.exe
    					Solution 2:[2]
As far as I'm aware:
In library.cpp there is no (explicit) instantiation of the class template, or the member function of said class.
template class __attribute__((dllexport)) TestClass<int>;
Would be an (explicit) 'template specialization forward declaration'... (Because of course it would).
Long story short, if (and that's a bold assumption) I'm right you just need to add {} after TestClass<int> to have the type "defined".
To answer:
Why does the out-of-body definition of TestClass::other_member break export of TestClass::member?
I'm even less confident. But why are you defining a member function of a specialization of TestClass? ? Does it need a template at all?
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source | 
|---|---|
| Solution 1 | Brecht Sanders | 
| Solution 2 | 
