Using Templated Classes and Functions in a Shared Object/DLL
I am working on a fairly significantly-sized project which spans many shared libraries. We also have significant reliance on the STL, Boost and our own template classes and functions. Many exported classes contain template members and exported functions contain template parameters.
Here is a stripped-down example of how I do library exporting:
#if defined(_MSC_VER) && defined(_DLL)
// Microsoft
#define EXPORT __declspec(dllexport)
#define IMPORT __declspec(dllimport)
#elif defined(_GCC)
// GCC
#define EXPORT __attribute__((visibility("default")))
#define IMPORT
#else
// do nothing and hope for the best at link time
#define EXPORT
#define IMPORT
#endif
#ifdef _CORE_COMPILATION
#define PUBLIC_CORE EXPORT
#define EXTERNAL_CORE
#else
#define PUBLIC_CORE IMPORT
#define EXTERNAL_CORE extern
#endif
#include <deque>
// force exporting of templates
EXTERNAL_CORE template class PUBLIC_CORE std::allocator<int>;
EXTERNAL_CORE template class PUBLIC_CORE std::deque<int, std::allocator<int> >;
class PUBLIC_CORE MyObject
{
private:
std::deque<int> m_deque;
};
SO, my problem is that when I compile in Visual Studio (both 2008 and 2010), I get the following warning:
warning C4251: 'std::_Deque_val<_Ty,_Alloc>::_Almap' : class 'std::allocator<_Ty>' needs to have dll-interface to be used by clients of class 'std::_Deque_val<_Ty,_Alloc>'
Which seems to imply that I haven't exported std::allocator<int>
, which I have. And it's not like my exporting is incorrect, since not including
EXTERNAL_CORE template class PUBLIC_CORE std::allocator<int>;
EXTERNAL_CORE template class PUBLIC_CORE std::deque<int, std::allocator<int> >;
yields the warning:
warning C4251: 'MyObject::m_deque' : class 'std::deque<_Ty>' needs to have dll-interface to be used by clients of class 'MyObject'
The only thing I can think of is that the _Ty
the warning about the std::allocator
is talking about is somehow not int
, but I can't seem to find any indication that it would be otherwise, since a std::deque<int>
would logically allocate with an std::allocator<int>
.
A consuming application can use the class just fine, but I have a gut feeling that this warning should not be ignored. When compiling with g++ in Linux, no errors are emitted (although that doesn't mean it's working right). Is g++ automatically doing something that MSVC cannot do? I've been targeting GCC on Linux, LLVM on OSX and MSVC on Windows, but I could potentially move to MinGW for Windows development, so abandoning MSVC is not exactly out of the question (if this proves to be too开发者_C百科 big of an inconvenience).
As you may know, the templates in your export file are in fact a 'permission to fill in whatever you think necessary' for the compiler.
That means that if you compile your header file with compiler A, it may instantiate a completely different deque<int>
than compiler B. The order of some members may change, for one, or even the actual type of some member variables.
And that's what the compiler is warning you for.
EDIT: addes some consequences to the explanation
So your shared libraries will only work together nicely when compiled by the same compiler. If you want them to work together, you can either make sure that all client code 'sees' the same declaration (through using the same stl implementation), or step back from adding templates to your API.
精彩评论