Шаблоны C и ошибка компоновщика

#c

#c

Вопрос:

Пожалуйста, рассмотрите следующую программу на C :

 #include <iostream>
using namespace std;

template <class T> class Array
{
    T *pType;
    int itsSize;
public:
    // template <class T>
    friend ostream amp;operator<< (ostream amp;, Array<T> amp; );
};

template <class T>
ostream amp;operator<<  (ostream amp;output, Array<T> amp;theArray)
  {
    return (output);
  }

ostream amp;operator<< (ostream amp;, Array<int> amp;);


int main ()
{
    Array<int> theArray;
    cout << theArray << endl;
    return 0;
}
  

Приведенный выше код компилируется, но компоновщик выдает следующую ошибку:

неопределенный символ `operator<<(std::ostreamamp;, Arrayamp;)’

Я считаю, что мне нужно указать компилятору создать экземпляр функции для operator << но я не знаю, как это сделать.

Боб

Комментарии:

1. это довольно независимо от шаблона. Вы объявляете функцию, но для нее нет определения.

2. Также подпись должна быть ostream amp;operator<< (ostream amp;, const Array<T> amp; );

Ответ №1:

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

Ваша строка

 ostream amp;operator<< (ostream amp;, Array<int> amp;);
  

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

Итак, компоновщик ищет этот другой оператор, но, конечно, не находит ни одного.

Если вы просто удалите это дополнительное объявление, оно должно работать намного лучше.

Ответ №2:

Объявление

 ostream amp;operator<< (ostream amp;, Array<int> amp;);
  

не сообщает компилятору о создании экземпляра шаблона. Он объявляет отдельную и отдельную не шаблонную функцию, т.Е. перегрузку.

Внутри main() использование operator<<() разрешает объявленную функцию. Компилятору не нужно специализировать шаблон для поиска соответствия. Однако, поскольку нет определения (т.Е. Реализации) этой функции, связывание завершается ошибкой.

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

Кстати, операторы потоковой передачи вывода обычно не изменяют выводимый объект. Поэтому рекомендуется изменить шаблон ostream amp;operator<< (ostream amp;, Array<T> amp; ) на ostream amp;operator<< (ostream amp;, const Array<T> amp; )

Кроме того, поскольку шаблоны (обычно) должны быть определены в файлах заголовков, а файлы заголовков включены в несколько исходных файлов, лучше избегать using namespace std и заменять ostream на std::ostream .

Ответ №3:

В вашем коде есть проблемы, @BoPersson и @Perter указали на некоторые.
Но даже если вы измените то, что они предложили (вот живая демонстрация на ideone), и я тоже запустил ее на своем VS 2015. Компиляторы все еще злятся.

Ideone говорит:

prog.cpp:10:55: предупреждение: объявление друга 'std::ostreamamp; operatoramp;)' объявляет не шаблонную функцию [-Wnon-template-friend]
 друг ostream amp;operator amp; );
 ^
prog.cpp:10:55: примечание: (если это не то, что вы намеревались, убедитесь, что шаблон функции уже объявлен, и добавьте после имени функции здесь) 
/home/FHMhT9/ccNwcxP0.o: в функции `main':
prog.cpp :(.text.startup  0x1b): неопределенная ссылка на `operatoramp;)'
collect2: ошибка: ld вернул 1 статус выхода

И VS тоже выдает почти те же ошибки.

Ideone сообщает мне, что объявление друга в классе объявляет не шаблонную функцию.

Итак, измените объявление в классе на:

 friend ostream amp;operator<< <T> (ostream amp;, Array<T> amp; );
//                        ^^^^^
// I added this <T> to tell the compiler that it is a template function.
  

Но вам нужно определить функцию перед этим, поэтому вырежьте реализацию operator<< , а затем вставьте ее перед классом. Но для этого вам понадобится прямое объявление класса. Итак, наконец, ваш код становится примерно таким:

И я Array<T> amp; const Array<T> amp; тоже изменил значение.

 #include <iostream>

template <typename T>
class Array;

template <class T>
std::ostream amp;operator<<  (std::ostream amp;output, const Array<T> amp;theArray)
{
    output << "abc";
    return (output);
}

template <class T> class Array
{
    T *pType;
    int itsSize;
public:
    // template <class T>
    friend std::ostream amp;operator<< <T> (std::ostream amp;, const Array<T> amp;);
};

int main()
{
    Array<int> theArray;
    std::cout << theArray << std::endl;
    return 0;
}
  

и эта версия теперь работает.