比如说,有一个第三方库在头文件中有以下内容:
foo.h
:
namespace tpl {
template <class T, class Enable = void>
struct foo {
static void bar(T const&) {
// Default implementation...
};
};
}
在我自己的库的界面中,我应该foo
为我自己的类型提供部分专业化。所以,假设我有:
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&);
};
}
whereML_GLOBAL
是编译器特定的可见性属性,以确保符号可用于动态链接(默认情况下,我的构建系统隐藏生成的共享库中的所有符号)。
现在,我不想透露我的实现bar
,所以我使用显式模板实例化:
xxx.cpp
:
# include "xxx.h"
namespace tpl {
void foo<::ml::xxx>::bar(::ml::xxx const&) {
// My implementation...
}
extern template struct foo<::ml::xxx>;
}
当需要tpl::foo<::ml::xxx>::bar
在某个消费者应用程序(我的共享库也链接到该应用程序)中实际使用此函数时,我得到符号的未定义引用错误。tpl::foo<::ml::xxx, void>::bar
实际上,在生成的共享库上运行时没有任何符号nm -CD
痕迹。tpl::foo<::ml::xxx, void>
到目前为止,我尝试过的是关于放置位置的不同组合ML_GLOBAL
(例如,在显式模板实例化本身上,关于 GCC 明显抱怨不像 Clang)和有/没有第二个模板参数void
。
问题是这是否与原始定义ML_GLOBAL
由于来自第三方库而没有附加可见性属性 ( ) 的事实有关,还是我实际上在这里错过了什么?如果我没有错过任何东西,那么我真的被迫在这种情况下公开我的实现吗?[... *咳嗽* 说实话看起来更像是编译器缺陷 *咳嗽* ...]