web-dev-qa-db-fra.com

Modèle de classe avec un ami de classe, que se passe-t-il vraiment ici?

Disons que je crée une classe pour un arbre binaire, BT, et que j'ai une classe qui décrit un élément de l'arbre, BE, quelque chose comme

template<class T> class BE {
    T *data;
    BE *l, *r;
public:
...
    template<class U> friend class BT;
};

template<class T> class BT {
    BE<T> *root;
public:
...
private:
...
};

Cela semble fonctionner; Cependant, j'ai des questions sur ce qui se passe en dessous.

J'ai d'abord essayé de déclarer l'ami comme

template<class T> friend class BT;

cependant, il semble nécessaire d'utiliser U (ou autre chose que T) ici, pourquoi? Cela implique-t-il que tout BT particulier est ami d'une classe BE particulière?

La page IBM consacrée aux modèles et aux amis contient des exemples de types de relations d'amis différents pour les fonctions mais pas pour les classes (et deviner une syntaxe n'a pas encore convergé vers la solution). Je préférerais comprendre comment adapter les spécifications au type de relation d'ami que je souhaite définir.

71
Michael Conlen
template<class T> class BE{
  template<class T> friend class BT;
};

N'est pas autorisé car les paramètres de modèle ne peuvent pas se masquer. Les modèles imbriqués doivent avoir des noms de paramètre différents.


template<typename T>
struct foo {
  template<typename U>
  friend class bar;
};

Cela signifie que bar est un ami de foo quels que soient les arguments de template de bar. bar<char>, bar<int>, bar<float>, et tout autre bar serait un ami de foo<char>.


template<typename T>
struct foo {
  friend class bar<T>;
};

Cela signifie que bar est un ami de foo lorsque l'argument de modèle de bar correspond à celui de foo. Seulement bar<char> serait un ami de foo<char>.


Dans ton cas, friend class bar<T>; devrait suffire.

97
Pubby

Afin de créer des liens avec une autre structure de même type:

#include <iostream>

template<typename T_>
struct Foo
{
    // Without this next line source.value_ later would be inaccessible.
    template<typename> friend struct Foo;

    Foo(T_ value) : value_(value) {}

    template <typename AltT>
    void display(AltT &&source) const
    {
        std::cout << "My value is " << value_ << " and my friend's value is " << source.value_ << ".\n";
    }

protected:
    T_ value_;
};

int main()
{
    Foo<int> foo1(5);
    Foo<std::string> foo2("banana");

    foo1.display(foo2);

    return 0;
}

Avec la sortie comme suit:

My value is 5 and my friend's value is banana. 

Dans template<typename> friend struct Foo; vous ne devriez pas écrire T après typename/class, sinon cela provoquerait une erreur d’observation des paramètres du template.

7
user6502769

Il n'est pas nécessaire de nommer les paramètres pour réduire le nombre de points d'échec lors du refactoring:

     template <typename _KeyT, typename _ValueT> class hash_map_iterator{
       template <typename, typename, int> friend class hash_map;
       ...
3
cpphilosophy