1

これは非常に短いスニペットで、g++ 4.7.1 ではコンパイルされません (ちなみに gcc 4.6.3 でもコンパイルされません)。

#include <iostream>

template<typename T>
struct Foo
{
    template<typename U>
    friend std::ostream& operator<<(Foo&, U&);
};

template<typename T, typename U>
std::ostream& operator<<(Foo<T> foo, U& u)
{
    std::cout << u;
    return std::cout;
}

int main()
{
    Foo<int> f;
    f << "bar";
    return 0;
}

そして、これが gcc 4.7.1 の出力です (4.6.3 はほぼ同じことを言っています)。

/tmp/ccNWJW6X.o: 関数main': main.cpp:(.text+0x15): undefined reference to内 std::basic_ostream >& operator<< (Foo&, char const (&) [4])' collect2: ld が 1 つの終了ステータスを返しました

誰でも理由を説明できますか?

編集

私もclang 3.1で試しましたが、まったく同じことが言えます。

4

2 に答える 2

8

テンプレートとの友情は少し複雑になる可能性があります...コードが何をするか見てみましょう:

template<typename T>
struct Foo {
    template<typename U>
    friend std::ostream& operator<<(Foo&, U&);  // [1]
};
template<typename T, typename U>
std::ostream& operator<<(Foo<T> foo, U& u) {    // [2]
    std::cout << u;
    return std::cout;
}

Fooたとえば、型を使用してインスタンス化する場合int、[1]のfriend宣言はテンプレート関数を宣言します。

template <typename U>
std::ostream& operator<<(Foo<int>&,U&);

しかし、その関数はどこにも存在しません。[2]で提供しているのは、2つの引数を取るテンプレートです。

template<typename T, typename U>
std::ostream& operator<<(Foo<T> foo, U& u);

重要な点は、テンプレートがインスタンス化されている間にフレンド宣言が処理され、その時点でFoo現在のインスタンス化で取得されたタイプを表すことです。

やりたいことにはさまざまなオプションがあります。最も簡単なのは、フレンド宣言を次のように変更することです。

template<typename W, typename U>
friend std::ostream& operator<<(Foo<W> foo, U& u);

Wこれは、2つの引数(両方ともここではバインドされていない)を取るテンプレートを宣言し、U名前空間レベルでの定義と一致します。

もう1つのオプションは、クラステンプレート定義内でフレンド関数を定義することです。この場合、元の署名を維持できます。さまざまな選択肢の詳細については、この他の回答をご覧ください

于 2012-09-07T02:44:22.503 に答える
1

Foo の出力 operator<< を実際に記述していません。

2 つの関数のシグネチャが大きく異なることに注意してください。

于 2012-09-07T02:36:55.587 に答える