3

私はクラスを持っており、頭の中で次のように定義されています:

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())を使用しようとすると、次のリンカーエラーが発生します。

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

コンパイラが自動的にこれを生成していないことに驚いています...私が間違っていることについて何か提案はありますか?

4

2 に答える 2

8

実装ファイルには、次のものがあります。

それが問題です。テンプレート定義をヘッダーファイルと実装ファイルの間で分割することはできません。テンプレートの性質上、C++コンパイラはここでは厄介です。ヘッダー内のすべてのコードを定義して、機能させます。

実際、ここでの問題は、C ++標準ではテンプレート情報を異なるユニット間で共有する方法が定義されていないため、すべてのテンプレート定義が同じコンパイルユニット内に存在する必要があることです。これらのユニットはリンカーによってつなぎ合わされますが、ジェネリックスはリンク時ではなくコンパイル時に解決されます(これは早い方です) 。

理論的には、C ++標準では、exportこれらのケースを処理するためのキーワード、を定義しています。実際には、これを実装するコンパイラはありません(1つの例外を除いて?)。コストと有用性のトレードオフが十分でないと見なされるため、これを変更する意図はありません。

于 2009-02-15T16:31:02.290 に答える
1

テンプレートが多すぎます-これは機能します:

#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;
}
于 2009-02-15T16:37:12.807 に答える