Entry tags:
Трабла с темплейтами (программистам C++)
Возникает ошибка линковки:
error LNK2005: public: __thiscall ArrayHolder<char>::ArrayHolder<char>(void)" (??0?$ArrayHolder@D@@QAE@XZ) already defined in excel.obj
Причины я знаю (ниже), вопрос в том, как их культурно лечить.
1. Есть DLL и прога, которая ее юзает (то же самое, когда другая DLL, юзает первую DLL).
2. В одном из хэдеров DLL (arrayholder.h) определен некий темплейтный класс:
template <class T>
class ArrayHolder<T>
{
public:
ArrayHolder() {}
...
};
3. В одном из хэдеров DLL (someclass.h) определен некий класс, унаследованный от ArrayHolder<char> - не напрямую а через цепочку, но это неважно:
class EXPORTIMPORT SomeClass: public ArrayHolder<char>
{
...
};
У этого класса в someclass.cpp определена куча функций, которые используются как в DLL, так и в проге.
4. В проге, в некоем модуле excel.cpp создается и используется объект типа ArrayHolder<char>.
Проблема, похоже, в следующем.
Когда компилируется DLL, компилятор создает код конструктора ArrayHolder::ArrayHolder() внутри DLL, и его код экспортируется наружу вместе с конструктором SomeClass,
Когда компилируется excel.cpp, компилятор не знает о том, что ArrayHolder::ArrayHolder() уже есть в DLL-ке, и создает его еще раз. Ошибка обнаруживается на этапе линковки.
Мне известно одно лекарство: надо сделать #include <someclass.h> в модуле excel.cpp. Тогда компилятор будет знать об этом экспорте уже на этапе компиляции.
Но это плохой путь, поскольку класс SomeClass реально не используется в модуле excel.cpp. Неочевидно, что, всякий раз, когда используешь ArrayHolder<char> надо добавить не только хэдер ArrayHolder, но и хэдеры всех классов в DLL, которые используют ArrayHolder<char>.
Upd: Как проблема решилась.
Вариант 1:
В конец arrayholder.h добавить:
class IMPORTEXPORT ArrayHolder_char_dummy: public ArrayHolder<char>
{
};
- в результате компилятор всегда будет знать, что эта специализация есть в DLL-ке.
Вариант 2:
(только для Microsoft Studio)
В конец arrayholder.h добавить:
#if EXPORT
template class IMPORTEXPORT ArrayHolder<char>;
#else
extern template class IMPORTEXPORT ArrayHolder<char>;
#endif
- результат тот же, правда, сыпятся warning-и, что 'nonstandard extension used'...
error LNK2005: public: __thiscall ArrayHolder<char>::ArrayHolder<char>(void)" (??0?$ArrayHolder@D@@QAE@XZ) already defined in excel.obj
Причины я знаю (ниже), вопрос в том, как их культурно лечить.
1. Есть DLL и прога, которая ее юзает (то же самое, когда другая DLL, юзает первую DLL).
2. В одном из хэдеров DLL (arrayholder.h) определен некий темплейтный класс:
template <class T>
class ArrayHolder<T>
{
public:
ArrayHolder() {}
...
};
3. В одном из хэдеров DLL (someclass.h) определен некий класс, унаследованный от ArrayHolder<char> - не напрямую а через цепочку, но это неважно:
class EXPORTIMPORT SomeClass: public ArrayHolder<char>
{
...
};
У этого класса в someclass.cpp определена куча функций, которые используются как в DLL, так и в проге.
4. В проге, в некоем модуле excel.cpp создается и используется объект типа ArrayHolder<char>.
Проблема, похоже, в следующем.
Когда компилируется DLL, компилятор создает код конструктора ArrayHolder::ArrayHolder() внутри DLL, и его код экспортируется наружу вместе с конструктором SomeClass,
Когда компилируется excel.cpp, компилятор не знает о том, что ArrayHolder::ArrayHolder() уже есть в DLL-ке, и создает его еще раз. Ошибка обнаруживается на этапе линковки.
Мне известно одно лекарство: надо сделать #include <someclass.h> в модуле excel.cpp. Тогда компилятор будет знать об этом экспорте уже на этапе компиляции.
Но это плохой путь, поскольку класс SomeClass реально не используется в модуле excel.cpp. Неочевидно, что, всякий раз, когда используешь ArrayHolder<char> надо добавить не только хэдер ArrayHolder, но и хэдеры всех классов в DLL, которые используют ArrayHolder<char>.
Upd: Как проблема решилась.
Вариант 1:
В конец arrayholder.h добавить:
class IMPORTEXPORT ArrayHolder_char_dummy: public ArrayHolder<char>
{
};
- в результате компилятор всегда будет знать, что эта специализация есть в DLL-ке.
Вариант 2:
(только для Microsoft Studio)
В конец arrayholder.h добавить:
#if EXPORT
template class IMPORTEXPORT ArrayHolder<char>;
#else
extern template class IMPORTEXPORT ArrayHolder<char>;
#endif
- результат тот же, правда, сыпятся warning-и, что 'nonstandard extension used'...
(no subject)
no subject
(ц) онегдод про доктора и больного
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)