0

次のコードが与えられます。

#include <iostream>
template<typename T>
class Foo 
{
public:
    Foo(const T& 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_;
};

コンパイラは、次の構文を使用せずに、テンプレート パラメーターを持つ両方のフレンド関数を問題なくコンパイルします。

template <typename T>
friend Foo<T> operator+ (const Foo<T>& lhs, const Foo<T>& rhs)

また

friend Foo<T> operator+ <>(const Foo<T>& lhs, const Foo<T>& rhs)

また

friend Foo<T> operator+ <T>(const Foo<T>& lhs, const Foo<T>& rhs)

テンプレートクラス自体の内部で実装によって定義されているためです。

コンパイラは、テンプレート宣言を含めずに、これらのフレンド関数をテンプレート パラメーターでコンパイルするにはどうすればよいでしょうか? クラス内に実装するだけで十分なのはなぜですか?

この概念については、 「テンプレート フレンドを使用するとリンカー エラーが発生するのはなぜですか?」のセクションで学びました。

4

1 に答える 1

2

これらの 2 つのオプションは、 を使用する場合と使用しないtemplate<class T>場合で、わずかに異なることを行います。

そのように関数を導入する場合friend、ADL (引数依存ルックアップ) を介してのみ到達可能な方法で、囲んでいる名前空間内に導入します。

template<class T>関数テンプレートを導入し、ないものは実際の関数を導入します。

したがって、この:

template<class T>
struct foo {
  friend void bar(foo<T>){}
};

foo<int>存在する場合、関数bar(foo<int>)が作成されることを意味します。次に、foo<double>を作成しますbar(foo<double>)

これらbarの はそれぞれ関数ではありませんtemplate。それらは、あなたが書いた場合と同様に、固定された署名、新しいオーバーロードを持つ関数です。

void bar(foo<char>){}

直後foo。例外は、friend bar競合とオーバーロードの解決がどのように機能するかを変更する ADL を介してのみ見つけることができることです。

今これ:

template<class T>
struct foo {
  template <typename X>
  friend void bar(foo<X>){}
};

template barのインスタンスごとにを作成しますfoo。これらは ADL を介してのみ検出されるため、競合しません。そして、見つけることができる唯一のものは、 が にT一致するものですX(この場合、より多くの引数を使用すると、異なる可能性があります)。

template私の経験では、バージョンを実行することはめったに良い考えではありません。

于 2015-04-08T03:30:14.700 に答える