Если класс является шаблонным, ваши пользователи, по сути, должны его скомпилировать (и это буквально верно в наиболее широко используемых реализациях C ++), и поэтому им нужны ваши внешние зависимости.
Самое простое решение - поместить основную часть реализации вашего класса в не шаблонный базовый класс (или инкапсулированный объект-член некоторого класса). Решите проблему скрытия модулей там.
А затем напишите производный от шаблона (или включающий) класс, чтобы добавить к нему безопасность типов.
Например, предположим, что у вас есть шаблон, который предоставляет удивительную возможность выделять при первом доступе (, опуская необходимый конструктор копирования, назначение, деструктор ):
template <class T>
class MyContainer
{
T *instance_;
public:
MyContainer() : instance_(0) {}
T &access()
{
if (instance_ == 0)
instance_ = new T();
return *instance_;
}
};
Если вы хотите, чтобы «логика» была разделена на базовый класс, не связанный с шаблоном, вам нужно было бы параметризовать поведение не шаблонным способом, то есть использовать виртуальные функции:
class MyBase
{
void *instance_;
virtual void *allocate() = 0;
public:
MyBase() : instance_(0) {}
void *access()
{
if (instance_ == 0)
instance_ = allocate();
return instance_;
}
};
Затем вы можете добавить понимание типа во внешний слой:
template <class T>
class MyContainer : MyBase
{
virtual void *allocate()
{ return new T(); }
public:
T &access()
{ return *(reinterpret_cast<T *>(MyBase::access())); }
};
т.е. Вы используете виртуальные функции, чтобы шаблон мог «заполнять» зависящие от типа операции. Очевидно, что этот шаблон действительно имеет смысл, только если у вас есть бизнес-логика, которую стоит скрыть.