5

非表示のデータをタイプTのオブジェクトに生成するが、データを他のすべてのオブジェクトから非表示にするタイプAが必要です。私のC++コンパイラはたまたまGCC4.4ですが、それは問題ではありません。なぜこれが機能しないのですか?

#include <iostream>

template <class T> class A {
  private:
    int n1;
  public:
    friend class T;
    A(const int n0 = 0) : n1(n0) {}
};

class B {
  public:
    int f(const A<B> a) const { return a.n1; }
    B() {}
};

int main() {
    const A<B> a(5);
    const B b;
    const int m = b.f(a);
    std::cout << m << "\n";
    return 0;
}

ちなみに、これはデータムを非表示にできないことを除いて、正常に機能します。

#include <iostream>

template <class T> class A {
  private:
    int n1;
  public:
    int n() const { return n1; }
    A(const int n0 = 0) : n1(n0) {}
};

class B {
  public:
    int f(const A<B> a) const { return a.n(); }
    B() {}
};

int main() {
    const A<B> a(5);
    const B b;
    const int m = b.f(a);
    std::cout << m << "\n";
    return 0;
}

C ++では、コンパイル時にテンプレートパラメータとしてフレンドクラスを指定することは本当に許可されていませんか?なぜだめですか?そうでない場合は、データムを非表示にするためにどのような代替手法を使用する必要がありますか?(可能であれば、コンパイル時の手法をお勧めします。)

ここでの私の誤解は何ですか?

(ここここに関連する質問への回答がいくつかありますが、それらが私の特定の質問に答えていないか、答えていることを理解できていません。とにかく、私はまったく間違ったテクニックを使用している可能性があります。友達のクラスTが失敗する理由、私が本当に知りたいのは、友達と一緒であろうと他の手段であろうと、データを非表示にする方法です。)

ありがとう。

4

2 に答える 2

4

あなたのコンパイラは単に古すぎます。C++11 では、テンプレート パラメーターをフレンドとして宣言できます。

§11.3 [class.friend] p3

関数を宣言しないフレンド宣言は、次のいずれかの形式になります。

  • friend elaborated-type-specifier ;
  • friend simple-type-specifier ;
  • friend typename-specifier ;

宣言の型指定子が (おそらく cv 修飾された) クラス型を指定する場合、そのクラスは;friendとして宣言されます。friendそれ以外の場合、friend 宣言は無視されます。

また、テンプレート パラメーターの例もフレンドとして含まれています。

class C;
// [...]
template <typename T> class R {
  friend T;
};

R<C> rc;   // class C is a friend of R<C>
R<int> ri; // OK: "friend int;" is ignored

残念ながら、C++03 にはこれを行う方法がありませんが、単純に 1 つのフリー関数をフレンドリにして、あるクラスからデータを取得して別のクラスに渡す「グルー」コードとして機能させることができます。もう 1 つの方法は、パスキー パターンです。

于 2012-03-17T22:28:46.993 に答える
1

エラーの背後にある標準はわかりませんが (Xeo の回答を参照)、C++03 の回避策を見つけました。Tフレンドを作成する代わりに、Tのメンバー関数の 1 つをフレンドにします。

#include <iostream>

template <class T> class A {
  private:
    int n1;
  public:
    friend int T::getN1(const A& a) const;
    A(const int n0 = 0) : n1(n0) {}
};

class B {
  public:
    int f(const A<B> a) const { return getN1(a); }
    B() {}
  private:
    int getN1(const A<B>& a) const {return a.n1;}
};

class C {
  public:
    int f(const A<B> a) const { return getN1(a); }
    C() {}
  private:
    // Error, n1 is a private member of A<B>
    int getN1(const A<B>& a) const {return a.n1;}
};

int main() {
    const A<B> a(5);
    const B b;
    const int m = b.f(a);
    std::cout << m << "\n";
    return 0;
}

または、T のネストされたクラス/構造体を A のフレンドにすることもできます。これは、T にアクセスさせたい A のプライベート メンバーがいくつかある場合により便利です。

#include <iostream>

template <class T> class A {
  private:
    int n1;
  public:
    friend class T::AccessToA;
    A(const int n0 = 0) : n1(n0) {}
};

class B {
  public:
    int f(const A<B> a) const { return AccessToA::getN1(a); }
    B() {};
  private:
    friend class A<B>;
    struct AccessToA
    {
        static int getN1(const A<B>& a) {return a.n1;}
    };
};

class C {
  public:
    int f(const A<B> a) const { return AccessToA::getN1(a); }
    C() {};

  private:
    friend class A<C>;
    struct AccessToA
    {
        // Error, n1 is a private member of A<B>
        static int getN1(const A<B>& a) {return a.n1;}
    };
};

int main() {
    const A<B> a(5);
    const B b;
    const int m = b.f(a);
    std::cout << m << "\n";
    return 0;
}
于 2012-03-17T22:12:54.527 に答える