Статическая переменная-член в шаблоне с несколькими DLL

Мой код построен на нескольких файлах .dll, и у меня есть класс шаблона со статической переменной-членом.

Я хочу, чтобы один и тот же экземпляр этой статической переменной-члена был доступен во всех dll, но это не работает: я вижу разные экземпляры (разные значения) в каждой из них.

Когда я не использую шаблоны, нет проблем: инициализируйте статический член в одном из исходных файлов и используйте директивы __declspec (dllexport) и __declspec (dllimport) в классе. Но с шаблонами это не работает. Есть ли способ заставить его работать?

Я видел некоторые предлагаемые решения, в которых используется «extern», но я думаю, что не могу его использовать, потому что мой код должен работать с Visual Studio 2002 и 2005.

Спасибо.

Уточнение: я хочу иметь отдельный экземпляр статической переменной для каждого типа создания экземпляра шаблона. Но если я создаю экземпляр шаблона с одним и тем же типом в двух разных dll, я хочу, чтобы в них обоих была одна и та же переменная.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
18
0
7 460
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Ответ принят как подходящий

Создайте специализацию шаблона, а затем экспортируйте статические элементы специализации.

Спасибо, это работает. Но таким образом я должен создать специализацию для каждого типа, и я теряю весь смысл шаблонов. Есть ли решение без него?

Igor Oks 29.12.2008 21:54

см. ссылку в решении, которое я упомянул, чтобы сохранить гибкость шаблона

balint.miklos 30.06.2009 22:07

Я вижу два исправления этой проблемы.

Во-первых, вы используете другой класс, не являющийся шаблоном, для хранения этого статического значения - или делаете его глобальным? - и экспортировать это из 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++, и я не уверен, что это должно означать :)

Johannes Schaub - litb 29.12.2008 20:24

если вы хотите явно создать экземпляр всего шаблона, вы делаете это с помощью класса шаблона SpecialFooList <int>;

Johannes Schaub - litb 29.12.2008 20:24

Хорошо, исправлены (серьезные) ошибки кодирования, спасибо за внимание.

Daemin 29.12.2008 20:32

Спасибо. Я попытался создать только статический экземпляр, но это не решило проблему (другая dll не находит его во время связывания). Даже после исправления вы по-прежнему создаете экземпляр шаблона, а не статического объекта. Вы уверены, что он работает? Относительно вашего вопроса: я использую только один процесс

Igor Oks 29.12.2008 20:47

я вне игры. Я понятия не имею, как все работает в DLL Windows :) удачи. Я немного поиграю с ними в следующий раз.

Johannes Schaub - litb 29.12.2008 20:50

litb: спасибо! Кроме того, есть идеи, как заставить это работать с файлами unix .so?

Igor Oks 29.12.2008 20:53

Игорь: Просто мое мнение, что я бы избегал статических членов внутри dll, которые также доступны извне. Значит ли это, что единовременно будет работать только один экземпляр вашего процесса?

Daemin 01.01.2009 15:42

Проблема в том, что каждый отдельный экземпляр шаблона представляет собой отдельный тип со своей собственной статической переменной, которая не используется совместно с другими экземплярами, имеющими другие параметры шаблона. Вы можете предоставить не шаблонный базовый класс, содержащий статическую переменную.

ааа, вот что он имел в виду! я смотрел на его вопрос, не зная, что он имеет в виду. Я думаю, ты справился. красивый

Johannes Schaub - litb 29.12.2008 20:23

Нет, я хочу иметь отдельный экземпляр статической переменной для каждого типа создания экземпляра шаблона. Но если я создаю экземпляр шаблона с одним и тем же типом в двух разных dll, я хочу, чтобы в них обоих была одна и та же переменная.

Igor Oks 29.12.2008 20:41

Вы уже пробовали это использование:

#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), но я публикую в надежде, что он может оказаться полезным.

Также существует следующее решение:

  • в библиотека: явно создать экземпляр некоторой специализации шаблона и поделиться им с dllexport
  • в основная программа:
    • если специализация доступна, она будет использоваться из библиотеки
    • если специализация недоступна, она компилируется в основной программе

Подробное описание того, как это сделать:

Блог Anteru Явное создание шаблона

Кажется, есть способ сделать это с меньшими ограничениями для кода, который использует класс шаблона.

Сделайте статический член указателем. Создайте глобальную карту с фиксированным известным типом, которую можно экспортировать из 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)

Другие вопросы по теме