Put this in a file called t.hpp:
#include <unordered_map>
extern template class std::unordered_map<int, int>;
std::unordered_map<int, int> getMap();
And this in t.cpp:
#include "t.hpp"
std::unordered_map<int, int> getMap()
{
return std::unordered_map<std::string, const Foo*>();
}
template class std::unordered_map<std::string, const Foo*>;
Then build it (on Linux):
g++ -std=c++11 -shared -fPIC -o t.so t.cpp
Then look at the constructors in the shared object:
objdump --syms --demangle t.so | grep '::unordered_map()'
If you compiled with GCC 4.9 it should show nothing at all. With GCC 5.1 or 5.3, it should show something like this:
8a w F .text 1b std::unordered_map<int, int>::unordered_map()
But with GCC 6.1 it shows something like this:
0 *UND* 0 std::unordered_map<int, int>::unordered_map()
That means the default constructor for the map is not emitted in the shared object, though it needs to be. This causes linking failures later, when using the shared object in an executable.
If you compile with -O1
or higher, the problem goes away (the constructor is inlined).
It seems like the explicit template instantiation in t.cpp
is inhibited by the no-implicit declaration in t.hpp
. A workaround I came up with is to #define SOMETHING
in t.cpp
before #include "t.hpp"
then use #ifndef SOMETHING
to guard the no-implicit declaration in t.hpp
. But this wasn't necessary with GCC before version 6, and I'm not sure it should be.
Is this a bug in GCC 6.1? Or is the code wrong?
Aucun commentaire:
Enregistrer un commentaire