テンプレートの特別な友情

友達は、クラスのメンバーに無制限にアクセスできます。したがって、友情は賢明に与えられるべきです。テンプレートに関して言えば、友情は特別です。

テンプレートの友情ルールについて書く前に、友情に関する一般的なルールを提示したいと思います.

<オール>
  • 友達宣言はクラスのどこでもできます。
  • 友情については、クラス内のアクセス権は考慮されません。
  • 友情は受け継がれません。クラスが派生クラスに友好度を付与すると、03 から 派生クラスは自動的に Base のフレンドにはなりません。
  • 友情は推移的ではありません。クラス10の場合 クラス A とクラス 26 のフレンドです クラス30のフレンドです 、クラス 42 自動的に class55 のフレンドではありません .
  • クラスまたはクラス テンプレートは、クラスまたはクラス テンプレート、関数または関数テンプレート、または型とフレンドシップを持つことができます。

    一般的な友情

    クラスまたはクラス テンプレートは、クラス テンプレートまたは関数テンプレートの各インスタンスにフレンドシップを付与できます。

    // generalFriendship.cpp
    
    #include <iostream>
    
    template <typename T> // (1)
    void myFriendFunction(T);
    
    template <typename U>  // (2)
    class MyFriend;
    
    class GrantingFriendshipAsClass {
    
     template <typename U> friend void myFriendFunction(U);
     template <typename U> friend class MyFriend;
    
     std::string secret{"Secret from GrantingFriendshipAsClass."};
    
    };
    
    template <typename T>
    class GrantingFriendshipAsClassTemplate{
    
     template <typename U> friend void myFriendFunction(U);
     template <typename U> friend class MyFriend;
    
     std::string secret{"Secret from GrantingFriendshipAsClassTemplate."};
    
    };
    
    template <typename T> // (3)
    void myFriendFunction(T){
     GrantingFriendshipAsClass myFriend;
     std::cout << myFriend.secret << '\n';
    
     GrantingFriendshipAsClassTemplate<double> myFriend1;
     std::cout << myFriend1.secret << '\n';
    }
    
    template <typename T> // (4)
    class MyFriend{
    public:
     MyFriend(){
     GrantingFriendshipAsClass myFriend;
     std::cout << myFriend.secret << '\n';
    
     GrantingFriendshipAsClassTemplate<T> myFriend1;
     std::cout << myFriend1.secret << '\n';
     }
    };
    
    int main(){
    
     std::cout << '\n';
    
     int a{2011};
     myFriendFunction(a);
    
     MyFriend<double> myFriend;
    
     std::cout << '\n';
    
    }
    

    行 (1) と行 (2) は、関数テンプレート 61 を前方宣言します。 およびクラス テンプレート75 関数テンプレート 82 行 (3) で定義され、クラス テンプレート 93 行(4)で。クラス 108116 関数テンプレート 125 を許可します およびクラス テンプレート134 友情147 友情のために、両方のテンプレートはプライベートメンバー 157 を直接呼び出すことができます クラスとクラス テンプレートの。

    161

    クラステンプレート 175 には落とし穴があります .通常、テンプレートの最初の型パラメーターを呼び出します180 .次のコード スニペットのように、クラス テンプレートと関数テンプレートに同じ型パラメーター名 191 を使用する場合 またはクラステンプレート 201 エラーが発生します。名前 213 223 の または 236 name240 を隠します クラス テンプレート 251 の .

    次のコード スニペットは、落とし穴を示しています。

    template <typename T>
    class GrantingFriendshipAsClassTemplate{
    
     template <typename T> friend void myFriendFunction(T);
     template <typename T> friend class MyFriend;
    
     std::string secret{"Secret from GrantingFriendshipAsClassTemplate."};
    
    };
    

    特別な友情

    特別な友情は、テンプレート パラメータのタイプに依存する友情です。

    // specialFriendship.cpp
    
    #include <iostream>
    
    template <typename T> void myFriendFunction(T);
    template <typename U> class MyFriend;
    
    
    class GrantingFriendshipAsClass {
    
     friend void myFriendFunction<>(int); // (1)
     friend class MyFriend<int>; // (2)
    
    private:
     std::string secret{"Secret from GrantingFriendshipAsClass."};
    
    };
    
    template <typename T>
    class GrantingFriendshipAsClassTemplate {
    
     friend void myFriendFunction<>(int);
     friend class MyFriend<int>;
     friend class MyFriend<T>; // (3)
    
    private:
     std::string secret{"Secret from GrantingFriendshipAsClassTemplate."};
    
    };
    
    template <typename T>
    void myFriendFunction(T) {
     GrantingFriendshipAsClass myFriend;
     std::cout << myFriend.secret << '\n'; // (4)
    
     GrantingFriendshipAsClassTemplate<T> myFriend1;
     std::cout << myFriend1.secret << '\n'; // (5)
    }
    
    template <typename T> // (6)
    class MyFriend { 
    public:
     MyFriend() {
     GrantingFriendshipAsClass myFriend; 
     std::cout << myFriend.secret << '\n';
    
     GrantingFriendshipAsClassTemplate<int> myFriendInt; 
     std::cout << myFriendInt.secret << '\n';
    
     GrantingFriendshipAsClassTemplate<T> myFriendT; 
     std::cout << myFriendT.secret << '\n';
     }
    };
    
    int main() {
    
     std::cout << '\n';
    
     int a{2011};
     myFriendFunction(a); 
    
     MyFriend<int> myFriend; 
    
     std::cout << '\n';
    
    }
    

    クラス263 関数テンプレート 274 の完全な特殊化に友情を与えます 283 の場合 (1 行目) とクラス テンプレート 299 302 の場合 (2行目)。同じことがクラス テンプレート 316 にも当てはまります。 .行 (3) は、320 の完全な専門化に友情を与えるため、特別です。 クラス テンプレート 333 と同じ型パラメータを持つ したがって、関数テンプレート 342 クラス 350 のシークレットを呼び出すことができます 366 の場合 378 の完全な特殊化です (4 行目) または 388 398 などの同じ型を持つ (5 行目)。対応する引数は、クラス テンプレート 409 に適用されます。 (6行目).

    Friend to Types

    クラス テンプレートは、その友情を型パラメーターに付与することもできます。

    // typeFriendship.cpp
    
    #include <iostream>
    
    template <typename T>
    class Bank {
     std::string secret{"Secret from the bank."};
     friend T;
    };
    
    class Account{
     public:
     Account() {
     Bank<Account> bank;
     std::cout << bank.secret << '\n'; // (1)
     }
    };
    
    int main(){
    
     std::cout << '\n';
    
     Account acc;
    
     std::cout << '\n';
    
    }
    

    クラス 416 型パラメーター T に友情を付与します。したがって、424 436 の秘密にアクセスできます 442 のインスタンス化 :454> (1行目).

    次は?

    次回の投稿では、テンプレートの複雑なコーナーの 1 つである従属名について書きます。