Ответ 1
Создайте специализированную специализацию и затем экспортируйте статические элементы специализации.
Мой код создан для нескольких DLL файлов, и у меня есть класс шаблонов, который имеет статическую переменную-член.
Я хочу, чтобы один и тот же экземпляр этой статической членной переменной был доступен во всех DLL, но он не работает: я вижу в каждом из них разные экземпляры (разные значения).
Когда я не использую шаблоны, нет проблем: инициализируйте статический член в одном из исходных файлов и используйте директивы __declspec (dllexport) и __declspec (dllimport) в классе. Но это не работает с шаблонами. Есть ли способ заставить его работать?
Я видел некоторые предлагаемые решения, которые используют "extern", но я думаю, что не могу использовать его, потому что мой код должен работать с visual studio 2002 и 2005.
Спасибо.
Уточнение: я хочу иметь другой экземпляр статической переменной для каждого экземпляра экземпляра каждого типа. Но если я создаю шаблон с тем же типом в 2 разных dll, я хочу иметь одну и ту же переменную в обоих из них.
Создайте специализированную специализацию и затем экспортируйте статические элементы специализации.
Существует также следующее решение:
Подробное описание того, как вы можете это сделать:
Проблема заключается в том, что каждый экземпляр шаблона другого типа имеет свою статическую переменную, которая не используется совместно с другими экземплярами, которые имеют разные параметры шаблона. Вы можете предоставить базовый класс без шаблона, содержащий статическую переменную.
Кажется, есть способ сделать это с меньшими ограничениями для кода, который использует класс шаблона.
Сделать статический член указателем. Создайте глобальную карту, которая имеет фиксированный известный тип и может быть экспортирована из DLL. Карта использует typeid() класса как ключ и адрес "глобальной переменной для каждого класса" в качестве значения. Инициализируйте статический член через функцию, которая проверяет, существует ли класс на карте, и если это заставляет вторую версию класса (во второй DLL) указывать на статическую переменную первой версии класса.
Таким образом, каждая DLL имеет отдельный статический объект, но каждая DLL также имеет указатель, и все указатели указывают на один и тот же статический объект.
Здесь некоторый псевдокод, если статический тип совпадает с параметром шаблона (но должен быть легко адаптирован для других случаев).
map<string,void*> dllexport the_map; // instantiate this once in a single DLL
T *set_the_global(T *candidate) {
map<string,void*>::iterator r = the_map.find(string(typeid(the_class<T>).name()));
if(r == the_map.end()) {
the_map[string(typeid(the_class<T>).name())] = (void*)candidate;
return candidate; // new class: use it as global storage location
} else {
return (T*)(r->second); // class already has global storage location
}
}
template <class T> class the_class {
virtual void something(); // so RTTI exists
static T *the_global; // use this! always points to the same object
static T one_per_dll; // only used in initialisation
};
template<class T> the_class<T>::one_per_dll;
template<class T> the_class<T>::the_global = set_the_global(&the_class<T>::one_per_dll)
Есть две исправления для этой проблемы, которые я вижу.
Во-первых, вы используете другой класс, который не является шаблоном, для хранения этого статического значения - или сделать его глобальным? - и экспортируйте это из DLL.
Другой немного сложнее, поскольку вы создаете экземпляр шаблона в коде и экспортируете созданные им шаблонные значения. Поэтому, чтобы привести пример, у меня был особый тип шаблона с шаблоном связанных списков и ему нужно было иметь статическое значение, совместно используемое в DLL. Я написал код для шаблонов, но он действительно используется только для небольшого количества типов. Я хотел бы создать классы как таковые:
template <class T> class Foo;
template<> class Foo<int> {};
Затем вы можете экспортировать статические переменные, содержащиеся внутри.
__declspec(dllexport) int Foo<int>::StaticMember = 0;
(Или что-то в этом роде, я немного ржав с dll export/import.)
Хотя реальный вопрос заключается в том, почему вы хотите это сделать, поскольку технически DLL может использоваться во всех процессах с одной копией, хранящейся в памяти. Вы действительно хотите, чтобы была только одна версия статического для всех процессов или одна на процесс?
Вы уже пробовали это использование:
#pragma data_seg(".JOE")
HWND hWndServer = NULL;
HHOOK hook = NULL;
#pragma data_seg()
#pragma comment(linker, "/section:.JOE,rws")
Обратите внимание, что переменная нуждается в пучке инициализации.
Дополнительная информация: http://msdn.microsoft.com/en-us/library/ms997537.aspx http://www.flounder.com/hooks.htm
Удачи.
До extern template
экземпляров, принимаемых в черновик проекта, Microsoft представила расширение для компилятора VС++.
Компилятор VС++ генерирует предупреждение, если используется нестандартное расширение; VS.NET(2003) и выше ссылаются на это предупреждение для подробностей. Это предупреждение также указано в VS 6.0.
Я лично никогда не пытался использовать это расширение, поэтому я не могу ручаться за это предложение. Очевидно, я ограничиваю этот ответ Microsoft Visual Studio (я видел комментарий от вас относительно Unix), но я публикую в надежде, что он может оказаться полезным.