Компилятор не создает шаблонный оператор ostream << - PullRequest
3 голосов
/ 15 февраля 2009

У меня есть класс, определенный в голове как:

template <typename T> class MyClass
{
   template <typename U> friend std::ostream& operator<<(std::ostream& output, const MyClass<U>& p);
   public:
      ...
}

В файле реализации у меня есть:

template <typename U> std::ostream& operator<<(std::ostream& output, const MyClass<U>& m)
{
   output << "Some stuff";
   return output;
}

Что выглядит довольно кошерно. Однако, когда я пытаюсь использовать этот оператор (например, std :: cout << MyClass ()), я получаю следующую ошибку компоновщика: </p>

Undefined symbols: std::basic_ostream<char, std::char_traits<char> >& operator<< <InnerType>(std::basic_ostream<char, std::char_traits<char> >&, MyClass<InnerType> const&)

Я удивлен, что компилятор не сгенерировал это автоматически для меня ... Какие-нибудь предложения относительно того, что я делаю неправильно?

Ответы [ 2 ]

8 голосов
/ 15 февраля 2009

В файле реализации у меня есть:

В этом проблема. Вы не можете разделить определения шаблонов между заголовочными файлами и файлами реализации. Из-за природы шаблонов компиляторы C ++ здесь привередливы. Определите весь код в заголовке, чтобы он работал.

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

Теоретически, стандарт C ++ определяет ключевое слово, export, для обработки этих случаев. На практике компилятор no реализует это (за одним исключением?), И нет намерения менять это, поскольку компромисс между стоимостью и полезностью не считается достаточно хорошим.

1 голос
/ 15 февраля 2009

Слишком много шаблонов - это работает:

#include <iostream>
using namespace std;
template <typename T> struct MyClass {

    friend ostream & operator << ( ostream & os, MyClass<T> & c ) {
        os << "MyClass\n";
        return os;
    }
};

int main() {
    MyClass <int> c;
    cout << c;
}
...