Как реализовать счетчик классов в DLL?

Пока что у меня есть:

// TypeCounter.h

template <typename Base>
class Counter : public Base
{
protected:
static int typeIndexCounter;
};

template <typename T, typename Base>
class Bridge : public Counter<Base>
{
public:
virtual ~Bridge() {}

virtual int GetTypeIndex() const
{
return TypeIndex();
}

static int TypeIndex()
{
static int typeIndex = typeIndexCounter++;
return typeIndex;
}
};

// static variable definition
template <typename Base>
int Counter<Base>::typeIndexCounter;

Вариант использования похож на:

class SBase
{ ... }
class S0 : public Bridge<S0, SBase>
{ ... }
class S1 : public Bridge<S1, SBase>
{ ... }
class S2 : public Bridge<S2, SBase>
{ ... }

Так что для каждого вида Base класс, я могу посчитать, сколько у него производных (если оно когда-либо создавалось, конечно).

Проблема в том, что это Counter класс находится в DLL.

Если у меня есть несколько пользователей этой DLL, то каждый пользователь будет создавать свои собственные Bridge а также Counterтогда TypeIndex() может быть разным среди этих пользователей для одного и того же T,

Я пытался поставить __declspec(dllexport) до Counter а также Bridge, но есть ошибки компиляции на стороне пользователя (сторона пользователя изменится export в import, определив макрос).
Несмотря на ошибки, это также неправильный подход, так как не следует экспортировать шаблон класса.

Поэтому я хочу убедиться, что TypeIndex() сохраняйте то же самое наверняка T, даже если есть много экземпляров для одного и того же TКак я могу достичь этого?

Спасибо!

0

Решение

Используйте карту для хранения информации. Это не включает никакого встроенного кода (за исключением миксина CRTP для регистрации и подсчета), но он должен избегать несовпадения различных частей.

Тем не менее, когда вы пишете «пользователи», вы не имеете в виду пользователей в смысле людей, которые имеют логин, верно? Причина в том, что это всегда только подсчет в одном процессе, разные процессы одного и того же или разных пользователей не влияют на это.

0

Другие решения

Это правда, что вы не можете экспортировать шаблон класса. Это даже бесполезно, поскольку у вас есть весь шаблон класса, записанный в заголовочном файле, поэтому для использования кода фактически не требуется экспорта.
Вместо этого вы должны экспортировать экземпляр класса, а затем использовать его с ключевым словом «extern»:

Это заголовочный файл при компиляции библиотеки:

class SBase{ ... }

template class __declspec(dllexport) Bridge<S0, SBase>;
class S0 : public Bridge<S0, SBase>
{ ... }
template class __declspec(dllexport) Bridge<S1, SBase>;
class S1 : public Bridge<S1, SBase>
{ ... }
template class __declspec(dllexport) Bridge<S2, SBase>;
class S2 : public Bridge<S2, SBase>
{ ... }

И это заголовочный файл при построении клиентского кода:

class SBase{ ... }

extern template class __declspec(dllimport) Bridge<S0, SBase>;
class S0 : public Bridge<S0, SBase>
{ ... }
extern template class __declspec(dllimport) Bridge<S1, SBase>;
class S1 : public Bridge<S1, SBase>
{ ... }
extern template class __declspec(dllimport) Bridge<S2, SBase>;
class S2 : public Bridge<S2, SBase>
{ ... }

Теперь компоновщик будет искать эти классы во всей вашей программе, а не только в модуле компиляции.

Это должно быть определено по типу, чтобы получить разные выходные данные с использованием одного и того же кода:

#ifdef LIBRARY_BUILD
#define EXPORT __declspec(dllexport)
#define TEMPLATE_EXPORT
#else
#define EXPORT __declspec(dllimport)
#define TEMPLATE_EXPORT extern
#endif

class SBase{ ... }

TEMPLATE_EXPORT template class EXPORT Bridge<S0, SBase>;
class S0 : public Bridge<S0, SBase>
{ ... }
TEMPLATE_EXPORT template class EXPORT Bridge<S1, SBase>;
class S1 : public Bridge<S1, SBase>
{ ... }
TEMPLATE_EXPORT template class EXPORT Bridge<S2, SBase>;
class S2 : public Bridge<S2, SBase>
{ ... }

Это должно быть сделано во ВСЕХ шаблонных классах со статическими членами, поэтому у всех шаблонных классов есть только ОДНО экземпляры членов, а не по одному на модуль компиляции.

Вы можете получить дополнительную информацию здесь:
классы и статические переменные в общих библиотеках

РЕДАКТИРОВАТЬ:
Перечитав ваш вопрос, я бы объявил extern вашего базового класса шаблона (так как это класс со статическим членом), а не конкретные:

TEMPLATE_EXPORT template class EXPORT Counter<SBase>;

Итак, теперь вы можете иметь любой производный класс SBase, и все будут полагаться на один и тот же класс Counter, без необходимости объявлять себя как extern.
Конечно, если SBase находится в какой-то библиотеке, он также должен быть объявлен как extern (обычным образом, просто __declspec (dllexport), так как это не шаблон).

0

По вопросам рекламы [email protected]