Мой код построен на нескольких файлах .dll, и у меня есть класс шаблона со статической переменной-членом.
Я хочу, чтобы один и тот же экземпляр этой статической переменной-члена был доступен во всех dll, но это не работает: я вижу разные экземпляры (разные значения) в каждой из них.
Когда я не использую шаблоны, нет проблем: инициализируйте статический член в одном из исходных файлов и используйте директивы __declspec (dllexport) и __declspec (dllimport) в классе. Но с шаблонами это не работает. Есть ли способ заставить его работать?
Я видел некоторые предлагаемые решения, в которых используется «extern», но я думаю, что не могу его использовать, потому что мой код должен работать с Visual Studio 2002 и 2005.
Спасибо.
Уточнение: я хочу иметь отдельный экземпляр статической переменной для каждого типа создания экземпляра шаблона. Но если я создаю экземпляр шаблона с одним и тем же типом в двух разных dll, я хочу, чтобы в них обоих была одна и та же переменная.





Создайте специализацию шаблона, а затем экспортируйте статические элементы специализации.
см. ссылку в решении, которое я упомянул, чтобы сохранить гибкость шаблона
Я вижу два исправления этой проблемы.
Во-первых, вы используете другой класс, не являющийся шаблоном, для хранения этого статического значения - или делаете его глобальным? - и экспортировать это из dll.
Другой вариант немного сложнее, поскольку вы создаете экземпляр шаблона в коде и экспортируете созданное значение (я) шаблона. Итак, чтобы привести пример, скажем, у меня был особый тип шаблонного класса связанного списка, и мне нужно было иметь статическое значение, совместно используемое в DLL. Я написал код для создания шаблона, но на самом деле он используется только для небольшого количества типов. Я бы создал экземпляры классов как таковых:
template <class T> class Foo;
template<> class Foo<int> {};
Затем вы можете экспортировать статические переменные, содержащиеся внутри.
__declspec(dllexport) int Foo<int>::StaticMember = 0;
(Или что-то в этом роде, я немного устарел с экспортом / импортом dll.)
Хотя реальный вопрос заключается в том, зачем вам это нужно, поскольку технически DLL может использоваться во всех процессах только с одной копией, хранящейся в памяти. Вы действительно хотите, чтобы была только одна версия статики для всех процессов или одна для каждого процесса?
вы можете явно создать экземпляр только static: template int SpecialFooList <int> :: staticMember; в одном файле cpp, тогда вам не нужно специализировать весь шаблон. то, что вы делаете в настоящее время, не соответствует C++, и я не уверен, что это должно означать :)
если вы хотите явно создать экземпляр всего шаблона, вы делаете это с помощью класса шаблона SpecialFooList <int>;
Хорошо, исправлены (серьезные) ошибки кодирования, спасибо за внимание.
Спасибо. Я попытался создать только статический экземпляр, но это не решило проблему (другая dll не находит его во время связывания). Даже после исправления вы по-прежнему создаете экземпляр шаблона, а не статического объекта. Вы уверены, что он работает? Относительно вашего вопроса: я использую только один процесс
я вне игры. Я понятия не имею, как все работает в DLL Windows :) удачи. Я немного поиграю с ними в следующий раз.
litb: спасибо! Кроме того, есть идеи, как заставить это работать с файлами unix .so?
Игорь: Просто мое мнение, что я бы избегал статических членов внутри dll, которые также доступны извне. Значит ли это, что единовременно будет работать только один экземпляр вашего процесса?
Проблема в том, что каждый отдельный экземпляр шаблона представляет собой отдельный тип со своей собственной статической переменной, которая не используется совместно с другими экземплярами, имеющими другие параметры шаблона. Вы можете предоставить не шаблонный базовый класс, содержащий статическую переменную.
ааа, вот что он имел в виду! я смотрел на его вопрос, не зная, что он имеет в виду. Я думаю, ты справился. красивый
Нет, я хочу иметь отдельный экземпляр статической переменной для каждого типа создания экземпляра шаблона. Но если я создаю экземпляр шаблона с одним и тем же типом в двух разных 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.aspxhttp://www.flounder.com/hooks.htm
Удачи.
До того, как экземпляры extern template были приняты в черновой вариант стандарта, похоже, что Microsoft реализовала расширение для компилятора VC++.
Компилятор VC++ выдаст предупреждение, если используется нестандартное расширение; VS.NET (2003) и выше см. Это описание предупреждение для подробностей. Это предупреждение также указано для VS 6.0.
Я лично никогда не пытался использовать это расширение, поэтому я не могу поручиться за это предложение. Очевидно, я ограничиваю этот ответ Microsoft Visual Studio (я видел ваш комментарий относительно Unix), но я публикую в надежде, что он может оказаться полезным.
Также существует следующее решение:
Подробное описание того, как это сделать:
Кажется, есть способ сделать это с меньшими ограничениями для кода, который использует класс шаблона.
Сделайте статический член указателем. Создайте глобальную карту с фиксированным известным типом, которую можно экспортировать из 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)
Спасибо, это работает. Но таким образом я должен создать специализацию для каждого типа, и я теряю весь смысл шаблонов. Есть ли решение без него?