Подтвердить что ты не робот

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

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

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

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

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

Спасибо.

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

4b9b3361

Ответ 1

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

Ответ 2

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

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

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

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

Ответ 3

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

Ответ 4

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

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

Ответ 5

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

Во-первых, вы используете другой класс, который не является шаблоном, для хранения этого статического значения - или сделать его глобальным? - и экспортируйте это из DLL.

Другой немного сложнее, поскольку вы создаете экземпляр шаблона в коде и экспортируете созданные им шаблонные значения. Поэтому, чтобы привести пример, у меня был особый тип шаблона с шаблоном связанных списков и ему нужно было иметь статическое значение, совместно используемое в DLL. Я написал код для шаблонов, но он действительно используется только для небольшого количества типов. Я хотел бы создать классы как таковые:

template <class T> class Foo;
template<> class Foo<int> {};

Затем вы можете экспортировать статические переменные, содержащиеся внутри.

__declspec(dllexport) int Foo<int>::StaticMember = 0;

(Или что-то в этом роде, я немного ржав с dll export/import.)

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

Ответ 6

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

#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

Удачи.

Ответ 7

До extern template экземпляров, принимаемых в черновик проекта, Microsoft представила расширение для компилятора VС++.

Компилятор VС++ генерирует предупреждение, если используется нестандартное расширение; VS.NET(2003) и выше ссылаются на это предупреждение для подробностей. Это предупреждение также указано в VS 6.0.

Я лично никогда не пытался использовать это расширение, поэтому я не могу ручаться за это предложение. Очевидно, я ограничиваю этот ответ Microsoft Visual Studio (я видел комментарий от вас относительно Unix), но я публикую в надежде, что он может оказаться полезным.