7

ist es möglich, eine partielle Template-Spezifikation irgendwie zu einer Freundesklasse zu machen? I.e. ist für Sie das folgende Template-Klasse habenC++ - Templates: Partielle Template-Spezifikationen und Friend-Klassen

template <class T> class X{ 
    T t; 
}; 

Jetzt haben Sie teilweise Spezialisierungen zum Beispiel für Zeiger

template <class T> class X<T*>{ 
    T* t; 
}; 

Was ich erreichen will, ist, dass jeder mögliche X<T*> ein Freund Klasse von X<S> für ANY ist S. I.e. X<A*> sollte ein Freund von X<B> sein.

Natürlich, dachte ich über eine gewöhnliche Vorlage Freund Erklärung in X:

template <class T> class X{ 
    template <class S> friend class X<S*>; 
} 

Dies ist jedoch nicht kompiliert, g ++ sagt mir dies:

test4.cpp: 34: 15: Fehler : Spezialisierung von 'template<class T> class X' muss auf Namespacebereich erscheinen

test4.cpp: 34: 21: error: Teil Spezialisierung 'X<S*>' erklärt 'Freund'

Ist dies überhaupt nicht möglich oder gibt es eine Umgehungsmöglichkeit?

Der Grund, warum ich frage ist, dass ich einen Konstruktor in X<T*> müssen, die diese Klasse von einem beliebigen X<S> erzeugt (S muss ein Subtyp von T sein).

Der Code sieht wie folgt aus:

template <class T> class X<T*>{ 
    T* t; 

    template<class S> 
    X(X<S> x) : t(&(x.t)) {} //Error, x.t is private 
} 

Nun wird der Compiler beschwert sich, natürlich, dass x.t nicht visibile im Konstruktor ist, da es privat ist. Deshalb brauche ich eine Teilspezialisierungs-Freundklasse.

+1

Ist eine 'get'-Funktion wirklich nicht in Frage? Das scheint mir viel sauberer zu sein und vermeidet den ganzen Wahnsinn der Template-Freunde. – pmr

+0

würde es vielleicht in diesem Beispiel funktionieren. Es kann jedoch Daten geben, die nicht der Öffentlichkeit zugänglich gemacht werden sollten, sondern nur Vorlagenspezialisierungen. Die Frage ist, ob dieses Verhalten irgendwie möglich ist. – gexicide

Antwort

3

In C++ können Sie den Zugriff über private hinaus auf vier Ebenen gewähren.

  • vollständig public Zugang
  • Zugriff innerhalb Vererbungshierarchie (protected, hier irrelevant)
  • zu einer Basisvorlage friend (siehe diese Antwort)
  • auf eine Nicht-Vorlage (PMR Antwort sehen) oder vollständig Fach friend

Es gibt keinen Mittelweg Wette (zu schwach Ihren Anwendungsfall zu lösen) ween die beiden letzteren Arten der Freundschaft.

Aus §14.5.4 des C++ - Standards :.

Friend declarations shall not declare partial specializations.

Mit der folgenden Deklaration können Sie implementieren, was Sie benötigen. Es gibt Ihnen eine freie Hand, um auf jede Spezialisierung Ihrer Vorlage von jeder anderen Spezialisierung zuzugreifen, aber immer noch nur innerhalb von X. Es ist etwas permissiver als das, wonach Sie gefragt haben.

template<class T> class X 
{ 
    template<class Any> friend class X; 
    public: 
     ... 
}; 
1

Wir definieren ein getter durch einen Schlüssel in X. definiert geschützt

#include <type_traits> 

template <class T> class X{ 
    T t; 
public: 
    struct Key { 
    template<typename S> 
    Key(const X<S>&) { 
     static_assert(std::is_pointer<S>::value, "Not a pointer"); 
    } 
    }; 

    const T& get(Key) const { return t; } 
    T& get(Key) { return t; } 
}; 

template <class T> class X<T*> { 
    T* t; 
public: 
    template<class S> 
    X(X<S>& x) : t(&(x.get(typename X<S>::Key(*this)))) {} 
}; 

int main() 
{ 
    X<int> x1; 
    X<int*> x2(x1); 
    return 0; 
} 

Dies hat noch einige Schwächen. Jeder mit einem X<T*> kann jetzt get verwenden. Aber das ist jetzt so verschleiert, dass niemand davon Notiz nimmt. Ich würde einen einfachen öffentlichen Getter wählen.

+1

Grundsätzlich kann jeder mit einem 'nullptr' ein' get' verwenden. Sieht aus, als hätten wir hier einen Wettbewerb in Permissivität. –

+0

@JirkaHanika Sie können versuchen, das mit einer 'null_ptr'-Überladung zu lösen, aber es würde nichts davon besser machen. – pmr

+1

Ja, jeder mit einem '0' Literal könnte immer noch das' get' verwenden. –