1

テンプレートクラス宣言内でフレンドテンプレート関数を次のように定義すると、コンパイルできます。

#include <iostream>

template <typename T>
class X {
public:
    X(int i) : n(i) {}

private:
    T n;

    template <typename U> 
    friend void doStuff(const X<T>& x, const U& u)
    {
        std::cout << (x.n + u) << std::endl;
    }
};

int main()
{
    X<int> x(1);
    doStuff(x, 3);
    return 0;
}

しかし、次のように、doStuff()クラスの宣言の直後に、クラスのデカラレーションの定義を移動するとX<>、コンパイルできません。

template <typename U>
template <typename T>
void doStuff(const X<T>& x, const U& u)
{
    std::cout << (x.n + u) << std::endl;
}

次のコードも同様です。

template <typename U, typename T>
void doStuff(const X<T>& x, const U& u)
{
    std::cout << (x.n + u) << std::endl;
}

doStuff()では、クラス宣言の外部でテンプレート関数をどのように定義する必要がありますか?

前もって感謝します。

4

2 に答える 2

5

おそらくこのように:

template <typename T>
class X {
public:
    X(int i) : n(i) {}

private:
    T n;

    template <typename U, typename V>
    friend void doStuff(const X<U>& x, const V& u);
};

template <typename U, typename V>
void doStuff(const X<U>& x, const V& u)
{
    std::cout << (x.n + u) << std::endl;
}

int main()
{
    X<int> x(1);
    doStuff(x, 3);
    X<double> y(1.0);
    doStuff(y, 3.5);
}
于 2012-10-13T17:30:01.430 に答える
3

@jrokは良い解決策を提供します。

なぜそれが機能するのか、そしてなぜそれが必要なのかを詳しく説明しましょう。

関数を次のように宣言することによって

template <typename U, typename V>
friend void doStuff(const X<U>& x, const V& u);

XとVごとに関数doStuffがあると言いますが、UがTでない場合はどうでしょうか?タイプX、intの引数を使用してdoStuffを呼び出す場合、テンプレート引数の推定の唯一の許容可能な結果は、クラス定義のタイプTをintに設定することです。

さて、なぜこれを行うだけではうまくいかないのですか?

template <typename V>
friend void doStuff(const X<T>& x, const V& u);

実はそうですね。しかし、それが意味するのは、どのタイプでも、必要なすべてのに対して、をとる関数を定義することをTコンパイラーに指示し、2番目のパラメーターがテンプレートパラメーターであるということです。最初の引数はテンプレート関数パラメーターではないことに注意してください。X<T>T

ユーザーがタイプのクラスを使用するときはいつでも、この特定のパターンを使用して、最初のパラメーターである関数doStuffを定義する方法一般的に言う方法はありません。X<T>X<T>

したがって、クラスでは、それが存在することを約束しましたが、テンプレート化された方法で定義を記述する方法はありません。それは次のようなものでなければなりません

template <typename T,typename U>
for_any_seen_template_instance_anywhere_in_the_program_< X<T> >:: 
      void doStuff(const X<U>& x, const V& u){
   ... code.
}

そのようなことはありません。それについて考える別の方法:あなたが書くとき

doStuff(a,b); 

最初のパラメーターが関数テンプレートパラメーターでない場合、その最初の引数に関して自動的に生成されるものはありません。クラステンプレートのテンプレートパラメータタイプは、テンプレート関数パラメータのように自動的に推定されません。

ただし、 (宣言で約束したように)必要なものはすべて定義できますが、必要なタイプごとに自分で定義する必要があります。X<T>T

template<typename V>
void doStuff(const X<int>& x, const V& u){
   std::cout << (x.n + u) << std::endl;
}

以下のコメントに答えて、編集してください。

doStuff(X<U>,int)たとえば、X<T>タイプTや。に関係なく、すべてが友達であることは事実ですU。これは、doStuffの本体内で、タイプのオブジェクトのプライベートにアクセスできることを意味しますX<Q>。この場合、そのようなオブジェクトを関数に渡さなかったが、そこで作成しX<std::string>て、そのプライベートで遊ぶことができた。これは、元々持っていたインラインを使用しない場合に支払う価格です。

于 2012-10-13T18:05:08.903 に答える