5

c++に関するよくある質問35.16

http://www.parashift.com/c++-faq-lite/template-friends.html

#include <iostream>

template<typename T>
class Foo {
public:
  Foo(T const& value = T());
  friend Foo<T> operator+ (const Foo<T>& lhs, const Foo<T>& rhs);
  friend std::ostream& operator<< (std::ostream& o, const Foo<T>& x);
private:
  T value_;
};

autorは主張します:

'この障害は、コンパイラがクラス定義でフレンドラインが適切に並んでいることを確認したときに発生します。その時点では、フレンド関数自体がテンプレートであるかどうかはまだわかりません(なぜですか?クラステンプレートのメンバー関数はデフォルトで関数テンプレートではありませんか?) ; これらは次のような非テンプレートであると想定しています。

Foo<int> operator+ (const Foo<int>& lhs, const Foo<int>& rhs)
{ ... }  

std::ostream& operator<< (std::ostream& o, const Foo<int>& x)
{ ... }

上記の非テンプレートはなぜですか?これらのテンプレートはintを介してインスタンス化されていませんか?

'operator+またはoperator<<関数を呼び出すと、この仮定により、コンパイラは非テンプレート関数の呼び出しを生成しますが、これらの非テンプレート関数を実際に定義したことがないため、リンカは「未定義の外部」エラーを返します。 。'

実際、コンパイラーに上記を関数テンプレートとして認識させるには、プログラマーは以下のように明示的にこれを行う必要があります。

template<typename T> class Foo;  // pre-declare the template class itself
template<typename T> Foo<T> operator+ (const Foo<T>& lhs, const Foo<T>& rhs);
template<typename T> std::ostream& operator<< (std::ostream& o, const Foo<T>& x);

誰か説明してもらえますか?これは非常に厄介で、コンパイラがTを「int」に置き換えてClass Fooのインスタンスをインスタンス化し、それを1日と呼んでいない理由がわかりません。

ありがとう。

4

1 に答える 1

5

クラステンプレートのメンバー関数はテンプレートの一部であるため、テンプレートを使用してインスタンス化されますが、フレンドはインスタンス化されません。テンプレート以外の場合を考えてみましょう。

struct S {
    friend void foo(S);
};

void foo(S)この時点で宣言する必要はないことに注意してください。friend宣言は、関数が定義されている場合void foo(S)その関数はにアクセスできることを示していますS。実際に定義されることはないかもしれませんが、それは問題ありません。

テンプレートの場合、状況は同じです。

template<typename T> struct S {
    friend void foo(S);
};

これは、どのタイプTも、関数void foo(S<T>)が定義されている場合、その関数はにアクセスできることを意味しますS<T>。その関数は、オーバーロードすることにより、具体的な関数であることが期待されます。

void foo(S<char>) { }
void foo(S<int>) { }

コンパイラは、後ですべてに使用できる関数テンプレートを提供することを計画していることを認識していませんT。代わりに、適切な関数テンプレートがすでに宣言されている場合は、山かっこを追加して指定するとインスタンス化されます。

テンプレートを前方宣言する必要がある理由については、「テンプレート」に1つの宣言だけが必要な理由はありません。検討:

#include <iostream>
template<typename T> struct S;
template<typename T> void foo(S<T>);
template<typename T> void foo(S<T *>);
template<typename T> struct S {
    friend void foo<>(S);
};
template<typename T> void foo(S<T>) { std::cout << "template template friend\n"; }
template<typename T> void foo(S<T *>) { std::cout << "template specialization template friend\n"; }
template void foo(S<void *>);
int main() {
    foo(S<int>());
    foo(S<void *>());
}

ここでは、の2つの特殊化があり、どちらかを選択できるfooように、両方を前方宣言する必要がありfriendます。

于 2012-08-08T12:26:33.520 に答える