So definieren Sie Freunde für Klassen, die in der Vorlagenklasse definiert sind

8

Angenommen, ich habe die folgende Vorlagenklasse, die eine geschachtelte Klasse definiert:

%Vor%

Angenommen, die von mir codierte Umgebung hat die folgende Hilfsklasse, die auf jeden Typ spezialisiert sein sollte, der eine spezielle Behandlung erfordert:

%Vor%

Wie kann ich maybeChangeType für foo<T>::bar spezialisieren? Es ist einfach genug, sich beispielsweise auf foo<int>::bar zu spezialisieren, aber foo wird mit mehr als 100% T verwendet, also ist das nicht wirklich eine Option.

HINWEIS: Bitte lesen Sie sorgfältig, bevor Sie diese Frage als Duplikat markieren. Diese Frage ist nicht und fragt, wie man sich im Allgemeinen spezialisieren soll (zB Vorlagen in C ++ verstehen ) oder wie man Freunde deklariert oder wie man Freunde von Vorlagen deklariert. Es fragt, wie man einen Freund für ein verschachteltes Mitglied einer Template-Klasse, die keine Vorlage ist, deklariert (wie der Titel angibt).

Der Versuch, Spezialisierungen auf "normale" Weise zu definieren, funktioniert nicht, weil foo<T>::bar kein ableitbarer Kontext ist (schlechtes Zeichen: es benötigt typename vor):

%Vor%

Wenn die Spezialisierung als Freund deklariert wird, entstehen auch Kompilierungsfehler:

%Vor%

Die obigen Fehler machen deutlich, dass die tatsächliche Definition dieser Freunde nicht stimmen darf:

%Vor%

Aber jetzt sind wir wieder da, wo wir angefangen haben: Jeder Versuch, eine Spezialisierung für foo<T>::bar zu definieren, wird fehlschlagen, weil% ce_de% in einem nicht ableitbaren Kontext verwendet wird.

HINWEIS: Ich kann das Problem für Funktionen umgehen, indem ich eine Inline-Friend-Überladung zur Verfügung stelle, aber das ist keine Hilfe für eine Klasse.

HINWEIS: Ich könnte das Problem umgehen, indem ich die innere Klasse in den Namespace-Bereich verlagere, aber das würde den Namespace erheblich verschmutzen (viele innere Klassen, mit denen der Benutzer wirklich kein Geschäft hat) und die Implementierung verkomplizieren (zB würden sie es tun) haben keinen Zugriff mehr auf private Mitglieder ihrer einschließenden Klasse und die Anzahl von bar -Deklarationen würde sich vermehren).

HINWEIS: Ich verstehe, warum es gefährlich / unerwünscht wäre, eine beliebige Spezialisierung des Namens friend zu erlauben (was wäre, wenn foo<T>::bar zB foo<T> hätte), aber in diesem Fall ist using bar = T wirklich eine Klasse ( nicht einmal eine Vorlage!), die foo wirklich definiert, also sollte es keine ODR-Haarigkeit geben oder das Risiko, dass die Spezialisierung andere (unbeabsichtigte) Typen beeinflussen würde.

Ideen?

    
Ryan 21.08.2015, 16:07
quelle

3 Antworten

3

Als intrusive Lösung können Funktionen zur Typ-Programmierung (Metaprogrammierung) verwendet werden. Sie könnten die Type-Funktion als Friend-Funktion schreiben:

%Vor%

Ersetze type_t<T> mit einem beliebigen type_t<my_type_function_result> . Es ist nicht notwendig, aber manchmal bequem, diese Funktion zu definieren, z.B. für Berechnungen in konstanten Ausdrücken. type_t kann mit Vergleichsoperatoren erweitert werden, um beispielsweise std::is_same<A, B> durch infix a == b zu ersetzen. Der Typ type_t<T> wird direkt aus zwei Gründen anstelle von T verwendet:

  1. Für eine Definition von maybeChangeType_adl ist es notwendig Konstruiere ein Objekt vom Rückgabetyp.
  2. Nicht alle Typen können von einer Funktion zurückgegeben werden. Z.B. abstrakte Typen, Funktionstypen, Array-Typen. Diese können immer noch als verwendet werden Vorlagenargumente.

In C ++ 14 würde ich Variablenvorlagen verwenden, um diese Funktion zu implementieren:

%Vor%

Obwohl dies etwas von der Symmetrie verliert (Parameter vs Rückgabetyp).

In jedem Fall können Sie den Typ wie folgt abfragen:

%Vor%

Eine Fallback-Funktion maybeChangeType kann bereitgestellt werden, um die primäre Vorlage im OP zu spiegeln:

%Vor%

Oder Sie spezialisieren eine maybeChangeType -Klassenvorlage auf das Vorhandensein der Funktion maybeChangeType_adl :

%Vor%     
dyp 21.08.2015 16:55
quelle
1

Wenn Sie den Vorlagenparameter T in bar exportieren können, und wenn Sie einen weiteren (voreingestellten) Vorlagenparameter zu maybeChangeType hinzufügen können, können Sie Folgendes versuchen:

%Vor%     
ex-bart 21.08.2015 16:32
quelle
0

Inspiriert von den Antworten von @ ex-bart und @dyp konnte ich die folgende C ++ 11-Lösung entwickeln:

%Vor%

Es hat den Vorteil, dass Endbenutzer oder Klassenimplementierungen nicht der schwarzen Magie ausgesetzt werden. Benutzer verwenden einfach maybeChangeType und Klassen können sie spezialisieren, indem sie einfach eine typedef other_type bereitstellen.

    
Ryan 21.08.2015 18:01
quelle