Klassenvorlage mit Vorlage Klassenfreund, was ist hier wirklich los?

80

Angenommen, ich erstelle eine Klasse für einen Binärbaum BTund habe eine Klasse, die ein Element des Baums beschreibt BE, so etwas wie

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:
...
};

Dies scheint zu funktionieren; Ich habe jedoch Fragen dazu, was darunter vor sich geht.

Ich habe ursprünglich versucht, den Freund als zu deklarieren

template<class T> friend class BT;

Wie auch immer, hier scheint es notwendig zu sein U(oder etwas anderes als T), warum ist das so? Bedeutet dies, dass eine bestimmte BTPerson mit einer bestimmten BEKlasse befreundet ist ?

Die IBM Seite zu Vorlagen und Freunden enthält Beispiele für verschiedene Arten von Freundschaftsbeziehungen für Funktionen, jedoch nicht für Klassen (und das Erraten einer Syntax für die Lösung ist noch nicht konvergiert). Ich würde es vorziehen zu verstehen, wie man die Spezifikationen für die Art der Freundschaftsbeziehung, die ich definieren möchte, richtig macht.

Michael Conlen
quelle

Antworten:

111
template<class T> class BE{
  template<class T> friend class BT;
};

Ist nicht zulässig, da sich Vorlagenparameter nicht gegenseitig beschatten können. Verschachtelte Vorlagen müssen unterschiedliche Namen von Vorlagenparametern haben.


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

Dies bedeutet, dass barein Freund foounabhängig von barden Vorlagenargumenten ist. bar<char>, bar<int>, bar<float>, Und andere barwürden Freunde von foo<char>.


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

Dies bedeutet, dass barein Freund davon ist, foowann bardas Vorlagenargument mit dem übereinstimmt foo. Nur bar<char>wäre ein Freund von foo<char>.


In Ihrem Fall friend class bar<T>;sollte ausreichend sein.

Pubby
quelle
2
Diese Konstruktion in meiner Code-Freund-Klasse BT <T> löst einen Fehler für den Freund-Zeilen-Fehler aus: 'BT' ist keine Vorlage, obwohl sie später als Vorlage <Klasse T> Klasse BT {...}
deklariert wird
2
Das Geheimnis ist also, dass ich BT deklarieren musste, um die Freundesklasse BT <T> verwenden zu können. Zeile in der BE, aber nicht für die Vorlage <Klasse U> Freund Klasse BT;. Danke für die Hilfe!
Michael Conlen
24
Genauer gesagt: Sie müssen die Deklaration template<typename T> class BT; vor der Definition von BE weiterleiten und dann friend class BT<T>; innerhalb der Klasse BE verwenden.
Bartosz Milewski
7

Um sich mit einer anderen Struktur vom gleichen Typ anzufreunden:

#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;
}

Mit der Ausgabe wie folgt:

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

In template<typename> friend struct Foo;sollten Sie nicht Tnach typename/ schreiben, classda dies sonst einen Fehler beim Abschatten der Vorlagenparameter verursacht.

user6502769
quelle
3
Bitte verbessern Sie Ihre Antwort.
SwiftBoy
genau das, wonach ich gesucht habe! ;)
jihlim
3

Es ist nicht erforderlich, die Parameter zu benennen, damit beim Refactoring weniger Fehlerquellen auftreten:

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

In meinem Fall funktioniert diese Lösung korrekt:

template <typename T>
class DerivedClass1 : public BaseClass1 {
  template<class T> friend class DerivedClass2;
private:
 int a;
};

template <typename T>
class DerivedClass2 : public BaseClass1 {
  void method() { this->i;}
};

Ich hoffe es wird hilfreich sein.

GutiMac
quelle
6
Wie soll diese Lösung richtig funktionieren, wenn Sie Vorlagenparameter schattieren und ansonsten den Freundschaftszugriff von DerivedClass2 auf DerivedClass1 nicht verwenden?
kornman00