Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
In diesem Artikel wird gezeigt, wie die Auslassungspunkte (...
) mit variadic Vorlagen von C++ verwendet werden. Die Auslassungspunkte haben viele Verwendungsmöglichkeiten in C und C++. Hierzu gehören Variablenargumentlisten für Funktionen. Die printf()
-Funktion der C-Laufzeitbibliothek ist eines der bekanntesten Beispiele.
Eine variadische Vorlage ist eine Klassen- oder Funktionsvorlage, die eine beliebige Anzahl von Argumenten unterstützt. Dieser Mechanismus ist besonders für C++-Bibliotheksentwickler nützlich: Sie können ihn sowohl auf Klassenvorlagen als auch auf Funktionsvorlagen anwenden und dadurch eine breite Palette von typsicheren und nicht trivialen Funktionen und Flexibilität bieten.
Syntax
Ein Auslassungszeichen wird auf zwei Arten von variadic-Vorlagen verwendet. Links neben dem Parameternamen kennzeichnet es ein Parameterpaket und rechts neben dem Parameternamen die Parameterpakete in separate Namen.
Nachfolgend finden Sie ein grundlegendes Beispiel für eine variadische Klassenvorlagendefinitionssyntax :
template<typename... Arguments> class classname;
Für Parameterpakete und Erweiterungen können Sie leerzeichen um die Auslassungspunkte hinzufügen, basierend auf Ihrer Einstellung, wie in diesem Beispiel gezeigt:
template<typename ...Arguments> class classname;
Oder in diesem Beispiel:
template<typename ... Arguments> class classname;
In diesem Artikel wird die Konvention verwendet, die im ersten Beispiel gezeigt wird (die Auslassungspunkte sind angefügt typename
).
In den vorherigen Beispielen Arguments
handelt es sich um ein Parameterpaket. Die classname
-Klasse kann eine variable Anzahl von Argumenten akzeptieren, wie in den folgenden Beispielen gezeigt.
template<typename... Arguments> class vtclass;
vtclass< > vtinstance1;
vtclass<int> vtinstance2;
vtclass<float, bool> vtinstance3;
vtclass<long, std::vector<int>, std::string> vtinstance4;
Mit einer variadischen Klassenvorlagendefinition können Sie auch mindestens einen Parameter benötigen:
template <typename First, typename... Rest> class classname;
Hier ist ein einfaches Beispiel für die Syntax der variadischen Funktionsvorlage :
template <typename... Arguments> returntype functionname(Arguments... args);
Das Arguments
Parameterpaket wird dann zur Verwendung erweitert, wie im nächsten Abschnitt gezeigt.
Andere Formen der variadischen Funktionsvorlagensyntax sind möglich , einschließlich, aber nicht beschränkt auf diese Beispiele:
template <typename... Arguments> returntype functionname(Arguments&... args);
template <typename... Arguments> returntype functionname(Arguments&&... args);
template <typename... Arguments> returntype functionname(Arguments*... args);
Bezeichner wie const
sind ebenfalls zulässig:
template <typename... Arguments> returntype functionname(const Arguments&... args);
Wie bei variadic-Vorlagenklassendefinitionen können Sie Funktionen ausführen, die mindestens einen Parameter erfordern:
template <typename First, typename... Rest> returntype functionname(const First& first, const Rest&... args);
Variadic-Vorlagen verwenden den Operator sizeof...()
(nicht verknüpft mit dem älteren sizeof()
-Operator):
template<typename... Arguments>
void tfunc(const Arguments&... args)
{
constexpr auto numargs{ sizeof...(Arguments) };
X xobj[numargs]; // array of some previously defined type X
helper_func(xobj, args...);
}
Weitere Informationen zur Platzierung von Auslassungszeichen
Zuvor wurde in diesem Artikel die Platzierung von Auslassungspunkten beschrieben, die Parameterpakete und Erweiterungen in dieser Form definieren: "links neben dem Parameternamen steht ein Parameterpaket und rechts neben dem Parameternamen, es erweitert die Parameterpakete in separate Namen". Technisch wahr, kann es bei der Übersetzung in Code verwirrend sein. Berücksichtigen Sie:
In einer Vorlagenparameterliste (
template <parameter-list>
)typename...
wird ein Vorlagenparameterpaket eingeführt.In einer Parameterdeklarationsklausel (
func(parameter-list)
) führt ein Auslassungszeichen der obersten Ebene ein Funktionsparameterpaket ein, und die Ellipsenpositionierung ist wichtig:// v1 is NOT a function parameter pack: template <typename... Types> void func1(std::vector<Types...> v1); // v2 IS a function parameter pack: template <typename... Types> void func2(std::vector<Types>... v2);
Wenn das Auslassungszeichen direkt nach dem Parameternamen angezeigt wird, haben Sie eine Parameterpaketerweiterung.
Beispiel
Eine gute Möglichkeit zur Veranschaulichung des variadischen Funktionsvorlagenmechanismus ist die Verwendung in einem Umschreiben einiger Funktionen von printf
:
#include <iostream>
using namespace std;
void print() {
cout << endl;
}
template <typename T> void print(const T& t) {
cout << t << endl;
}
template <typename First, typename... Rest> void print(const First& first, const Rest&... rest) {
cout << first << ", ";
print(rest...); // recursive call using pack expansion syntax
}
int main()
{
print(); // calls first overload, outputting only a newline
print(1); // calls second overload
// these call the third overload, the variadic template,
// which uses recursion as needed.
print(10, 20);
print(100, 200, 300);
print("first", 2, "third", 3.14159);
}
Output
1
10, 20
100, 200, 300
first, 2, third, 3.14159
Hinweis
Die meisten Implementierungen, die variadische Funktionsvorlagen enthalten, verwenden Rekursion einiger Formen, unterscheiden sich jedoch geringfügig von herkömmlichen Rekursionen. Die herkömmliche Rekursion umfasst eine Funktion, die sich selbst mit derselben Signatur aufruft. (Es kann überladen oder vorlageniert werden, aber die gleiche Signatur wird jedes Mal ausgewählt.) Variadische Rekursion umfasst das Aufrufen einer variadischen Funktionsvorlage mithilfe unterschiedlicher (fast immer abnehmender) Anzahl von Argumenten und dadurch jedes Mal eine andere Signatur ausstempeln. Eine "Basisfall" ist dennoch erforderlich, aber die Art der Rekursion ist anders.