Say, there is a third-party library that has the following in a header file:
foo.h
:
namespace tpl {
template <class T, class Enable = void>
struct foo {
static void bar(T const&) {
// Default implementation...
};
};
}
In the interface of my own library, I'm supposed to provide partial specialization of this foo
for my own type(s). So, let's say I have:
xxx.h
:
# include <foo.h>
namespace ml {
struct ML_GLOBAL xxx {
// Whatever...
};
}
namespace tpl {
template <>
struct ML_GLOBAL foo<::ml::xxx> {
static void bar(::ml::xxx const&);
};
}
where ML_GLOBAL
is a compiler-specific visibility attribute to ensure that the symbols are available for dynamic linkage (that is by default my build system hides all of the symbols in the produced shared library).
Now, I don't want to disclose my implementation of bar
, so I employ explicit template instantiation:
xxx.cpp
:
# include "xxx.h"
namespace tpl {
void foo<::ml::xxx>::bar(::ml::xxx const&) {
// My implementation...
}
extern template struct foo<::ml::xxx>;
}
When the time comes to actually use this tpl::foo<::ml::xxx>::bar
function in some consumer application (where my shared library is linked as well), I get the undefined reference error to the tpl::foo<::ml::xxx, void>::bar
symbol. And indeed, running nm -CD
on the produced shared library shows no trace of tpl::foo<::ml::xxx, void>
symbol.
What I've tried so far, were different combinations on where to put ML_GLOBAL
(e.g. on explicit template instantiation itself, about what GCC clearly complains unlike Clang) and with/without the second template argument void
.
The question is whether this is related to the fact that the original definition has no visibility attribute (ML_GLOBAL
) attached by virtue of coming from a third-party library or did I actually miss something here? If I didn't miss anything, then am I really forced to expose my implementation in such a scenario ? [... *cough* looks more like a compiler deficiency to be honest *cough* ...]