Переменная статического члена в шаблоне, с несколькими dll - PullRequest
18 голосов
/ 29 декабря 2008

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

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

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

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

Спасибо.

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

Ответы [ 7 ]

4 голосов
/ 30 июня 2009

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

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

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

Блог Антеру Явная реализация шаблона

3 голосов
/ 29 декабря 2008

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

2 голосов
/ 18 декабря 2009

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

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

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

1 голос
/ 29 декабря 2008

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

#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

Удачи.

1 голос
/ 29 декабря 2008

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

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

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

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

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

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

(Или что-то в этом роде, я немного устал от экспорта / импорта DLL).

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

0 голосов
/ 29 декабря 2008

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

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

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

...