0

C++ шаблон, ошибка линковки

126

Описание проблемы:

У меня возникла проблема с вызовом класса-шаблона, который я разработал. Я объявил новый тип Array, который является шаблоном.

В .hpp файле я определил класс следующим образом:

template <typename T>
class Array
{
public:
   Array();
};

В .cpp файле реализовал конструктор:

template <typename T>
Array<T>::Array()
{
    // Выполнить что-то
}

В функции main я пытаюсь создать объект:

Array<int> arr;

Однако при компиляции я получаю ошибку линковки: "разрешенный внешний символ для конструктора".

Есть ли у кого-нибудь идеи относительно решения данной проблемы?

5 ответ(ов)

0

Шаблонные функции, включая методы класса, должны быть полностью реализованы в заголовочных файлах. Это означает, что если у вас есть шаблонный класс, его реализация должна находиться целиком в заголовочном файле. Причина этого заключается в том, что компилятор должен иметь доступ ко всей определённой структуре шаблона (а не только к сигнатуре), чтобы сгенерировать код для каждого конкретного экземпляра шаблона.

0

Рекомендуется размещать и декларацию шаблона, и определения шаблонных функций в заголовочном файле. Большинство компиляторов C++ не поддерживают модель отдельной компиляции для шаблонов, что может привести к проблемам при линковке. Это связано с тем, что компилятор должен иметь доступ к полным определениям шаблонов во время компиляции для создания необходимых instantiations. Таким образом, если вам нужно создать шаблон, лучше всего держать как его объявление, так и определения в одном и том же заголовочном файле.

0

Проблема, с которой вы столкнулись, заключается в том, что вы скрыли определение конструктора в .cpp файле. Это определение применимо к всем типам T, включая T, когда он является int, но фактически не предоставляет никаких определений, так как это все еще только декларация.

Компоновщик не может найти символ Array<int>::Array().

Чтобы исправить это, можно добавить строку вроде этой:

Array<int> arr1;

в конец файла Array.cpp, и это заставит компилятор инстанцировать правильное определение, которое ищет компоновщик. Но это даст только одно определение для Array<int>, и ничего другого.

Это решение будет работать, пока вам не потребуется массив с другим параметром шаблона, скажем, double, в этом случае вам нужно будет добавить:

Array<double> arr2;

в конец файла Array.cpp - теперь вы можете увидеть, насколько это не устойчиво!

Если вам нужно, чтобы C++ работал с любым типом, который вы можете захотеть использовать в будущем, сейчас самое время переместить определение конструктора (и, скорее всего, все другие члены функций) в заголовочный файл (и удалить .cpp файл, так как в нем больше ничего не останется).

0

Как упоминалось выше, в шаблонах C++ процесс обработки новых методов выполняется компилятором на этапе компиляции. Проблема заключается в том, что компилятору необходимо знать все определения этих методов в этот момент времени, поэтому все объявления классов и функций должны находиться в файлах с расширением .h или .hpp.

0

Еще один вариант ответа: скомпилируйте только ваш .cpp файл (не главный) и проверьте размер объектного файла. Затем создайте пустой файл empty.cpp и скомпилируйте его. Наконец, сравните размеры обоих объектных файлов. Вы увидите, что они имеют одинаковый размер, что означает, что ваш .cpp файл не содержит ничего для компиляции, и линкер не может найти ничего для связывания.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь