Ich möchte also einen mehrdimensionalen Vektor mit einem gegebenen Typ erstellen, wobei die erste Dimension die Größe des ersten Arguments eines Funktionsaufrufs hat usw., zum Beispiel wenn ich
tue %Vor% x
sollte 6x10x15 sein 3D-Array (bestehend aus Nullen, weil ich jetzt standardmäßig konstruieren möchte)
Ich habe es versucht:
%Vor%Es scheint für 1 oder 2 Argumente zu funktionieren, aber scheitert für 3 Argumente mit folgendem Fehler (clang ++)
%Vor%Wenn ich richtig verstehe, ist das Problem, wenn der Compiler versucht, den Rückgabewert von make_vector zu berechnen, muss er den Rückgabewert des Vektors mit einer geringeren Anzahl von Argumenten kennen und dies nicht tun. Wie repariere ich das?
Erstellen Sie einen Namespace, um einige Helfer hinzuzufügen, genannt details
.
In details
erstellen Sie einen Typ struct adl_helper{};
Erstellen Sie eine Implementierung von make_vector
, außer dass der erste Parameter immer ein Vorlagenparameter namens Adl
ist. Dieser Vorlagenparameter wird niemals benannt, und Instanzen davon werden an Rekursionen übergeben.
Implementieren Sie make_vector( blah )
, indem Sie details::make_vector<T>( details::adl_helper{}, blah )
aufrufen.
Was hier passiert ist, dass ein scheinbar rekursiver Aufruf in der Signatur einer Template-Funktion in zwei Kontexten ausgewertet wird.
Zuerst wird ausgewertet, wo es deklariert ist. Insbesondere wird ausgewertet, bevor es selbst definiert wurde . Es "fängt" sich also nicht selbst.
Zweitens wird ein auf ADL (argument dependent lookup) basierender Durchlauf an dem Punkt durchgeführt, an dem er auf der Grundlage nur von Schablonentypen, die an die Funktion übergeben werden, instanziiert wird.
Die Typen template<class Adl>
und adl_helper
bedeuten, dass diese von einem Argument abhängige Suche die Funktion details::make_vector
selbst bei der Instantiierung sehen kann. Und wenn es den Rückgabetyp nachschlägt, kann auch details::make_vector
sehen. Etc.
Die Verwendung von class R=
aliases und ähnlichem dient nur dazu, den Code aufzuräumen und unnötige Duplizierung zu vermeiden.
In diesem speziellen Fall ist der Aufwand für den Rückgabetyp einfacher als all diese Gymnastik.
Ich denke diese Lösung ist sauberer :
%Vor%Interessante Frage! Das Problem, auf das Sie stoßen, ist, dass die Suche nach unqualifizierten Namen in den Bereichen, in denen sie verwendet wird, aussieht (in aufsteigender Reihenfolge der Allgemeinheit). Aber von [basic.scope.pdecl]:
Der Punkt der Deklaration für einen Namen steht unmittelbar hinter seinem vollständigen Deklarator (Klausel 8) und vor dessen Initialisierer (falls vorhanden)
und in dieser Funktion:
%Vor% Der "vollständige Deklarator" enthält den trailing-return-type. Daher wird die Funktionsvorlage make_vector<T, Args...>
erst im Bereich {
angezeigt. Deshalb wird dies nicht für 3+ Argumente kompilieren.
Der einfachste Fix wäre, wenn Sie Zugriff auf C ++ 14 hätten, würden Sie einfach den nachfolgenden Rückgabetyp nicht benötigen;
%Vor%Innerhalb des Rumpfes der Namensfunktion können Sie den rekursiven Aufruf ohne Probleme vornehmen.
Ohne C ++ 14 könnten Sie es an eine Klassenvorlage weiterleiten, deren Name im Bereich aller rekursiven Aufrufe liegt:
%Vor%Ich war mir über die anderen Antworten nicht bewusst, als ich das gepostet habe. Nicht löschen, falls es für jemanden nützlich sein könnte. Natürlich ist die Lösung mit C ++ 14 aktiviert.
Mit [unter dem Code] ( Demo @ ideone können Sie erreichen:
%Vor%Hier ist der Code mit minimalen Kommentaren:
%Vor%Die einfachste Lösung ist, zu C zurückzukehren:
%Vor% Wie gesagt, das ist in C ++ nicht möglich: Der C ++ - Standard verlangt, dass alle Array-Größen Kompilierzeitkonstanten sind. C ist in dieser Hinsicht sehr viel flexibler und erlaubt die Array-Laufzeitgrößen überall seit C99, sogar innerhalb von typedef
s.
Wenn ich also Code habe, der mit mehrdimensionalen Arrays ernsthaft arbeiten soll, frage ich mich ernsthaft, ob es sich lohnt, diesen Code in eine reine .c-Datei zu verschieben und sie einfach mit dem Rest meines Projekts zu verknüpfen.
Tags und Links c++ c++11 templates variadic-templates template-meta-programming