[C++] Разные определения шаблона

erotic

Добрый день.
Решил сделать сборку проекта с динамическими библиотеками под Windows, для этого перед большинством классов (кроме шаблонных или совсем маленьких встраиваемых) поставил макрос типа MY_LIB_EXPORT, который в зависимости от типа сборки определяется либо в "", либо в "__declspec(dllexport)", либо в "__declspec(dllimport)" (без кавычек, разумеется). В общем, классика.
Но вот вопрос:
есть библиотека A, она определяет class A_EXPORT Image, и еще в ней есть класс такого типа:
 

class A_EXPORT UseImage
{
public:
UseImage;
template<class T>
UseImage(const T&);
};


и есть включаемый файл с реализацией шаблона, который надо включать в код по мере надобности:
 
template <class T>
A::UseImage::UseImage(const T&)
{
Image i;
// SMTH
}

Теперь получается, что если я использую этот шаблонный конструктор внутри библиотеки A, то у меня в определении шаблона подразумевается __declspec(dllexport) Image, а если в другой библиотеки или программе, то там уже __declspec(dllimport) Image. На практике пока все собралось и отработало без косяков, но чревато ли это какими-либо проблемами?
На эти мысли меня навело вот что: в тестах проверяется этот конструктор, и раньше я файл с реализацией шаблона в тесты не включал. Выходило так, что шаблон использовался внутри A, там инстанциировался и потом в тестах использовалась готовая инстанция. А теперь, когда я сделал динамическую сборку, тесты не собрались без этой реализации, т.е. в тестах происходит еще одно инстанцирование.

tamusyav

Теоретически проблемы могут быть, но они, скорее всего, несущественны:
1. Если в шаблонной функции есть статические переменные, то они тоже продублируются (с соответствующими побочными эффектами).
2. Дублирование тела шаблонной функции приведет у увеличению суммарного объема библиотеки и использующего ее файле, а именно, одна инстанция будет в библиотеке, другая - в использующем ее файле, хотя их код будет, скорее всего, идентичен.
Больше пока ничего в голову не приходит.

vasena

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

erotic

Решение следующие: класс целиком не экспортируем, а экспортируем отдельные методы.
Это не решит моей проблемы с шаблоном, насколько я понимаю, т.к. из dll все равно можно получить только то, что явно экспортируется, а экспортировать шаблон я не могу, есессно. Разве что написать что-то типа __declspec(dllexport) template A::UseImage::UseImage<конкретный тип> чтобы попытаться экспортировать инстанциированный шаблон с конкретным параметром. Надо попробовать.

kokoc88

чтобы попытаться экспортировать инстанциированный шаблон с конкретным параметром
А зачем это нужно? Если посмотреть, то многие библиотеки boost работают с шаблонами и линкуются как dll-и без проблем. Я не понял, в чём у тебя возникла ошибка в тестах. Ты создавал и использовал конкретный код внутри библиотеки. Если ты создаёшь шаблон в другом месте, то все функции, которые использует этот шаблон, должны быть видны. По-другому это не работает, хотя действительно можно экспортировать конкретные специализации шаблонов.

erotic

Если ты создаёшь шаблон в другом месте, то все функции, которые использует этот шаблон, должны быть видны. По-другому это не работает, хотя действительно можно экспортировать конкретные специализации шаблонов.
Вообще-то - работает. Если он был инстанцирован в какой-либо библиотеке A, то использовать его в другой библиотеке или программе, которая линкуется к A, можно и без определения шаблона. Я на эту тему несколько экспериментов проводил с gcc со статической и с динамической сборками. В Visual Studio это тоже работает, раз работало до сих пор. Не работает только с .dll, т.к. там экспортируется только то, что ты явно скажешь.

kokoc88

Вообще-то - работает.
Не работает при динамической линковке. Мы же об этом говорим.

vasena

Писать надо так

class UseImage
{
public:
A_EXPORT UseImage;

template<class T>
UseImage(const T&);
};

// тут твои шаблонные методы или в другом файле, который сюда включишь

erotic

Писать надо так
Я не настолько туп, чтобы не понять, что означает
Решение следующие: класс целиком не экспортируем, а экспортируем отдельные методы.

erotic

Не работает при динамической линковке. Мы же об этом говорим.
А, ок, это верно.
Вообще, проблема не из того раздута. То, что определения должны быть видны, я понял в тот момент, когда у меня не собрался проект :))
Вопрос топика состоял в разных определениях шаблона и не в чем более.
Оставить комментарий
Имя или ник:
Комментарий: