Wie kann ich eine Funktion schreiben, die eine variable Anzahl von Argumenten akzeptiert? Ist das möglich, wie?
c++
variadic-functions
Nunos
quelle
quelle
Antworten:
Sie sollten es wahrscheinlich nicht tun, und Sie können wahrscheinlich sicherer und einfacher tun, was Sie möchten. Technisch gesehen schließen Sie stdarg.h ein, um eine variable Anzahl von Argumenten in C zu verwenden. Daraus erhalten Sie den
va_list
Typ sowie drei Funktionen, die darauf ausgeführt werdenva_start()
,va_arg()
undva_end()
.Wenn Sie mich fragen, ist das ein Chaos. Es sieht schlecht aus, ist unsicher und voller technischer Details, die nichts mit dem zu tun haben, was Sie konzeptionell erreichen möchten. Verwenden Sie stattdessen Überladung oder Vererbung / Polymorphismus, Builder-Muster (wie in
operator<<()
Streams) oder Standardargumente usw. Diese sind alle sicherer: Der Compiler erfährt mehr darüber, was Sie versuchen, sodass es mehr Gelegenheiten gibt, die er stoppen kann Sie, bevor Sie Ihr Bein abblasen.quelle
...
Syntax anzugeben ?printf()
beispielsweise analysiert die Funktion das Zeichenfolgenargument für spezielle Token, um herauszufinden, wie viele zusätzliche Argumente in der Liste der variablen Argumente zu erwarten sind.<cstdarg>
in C ++ anstelle von<stdarg.h>
In C ++ 11 haben Sie zwei neue Optionen, wie auf der Referenzseite für Variadic-Funktionen im Abschnitt Alternativen angegeben :
Unten sehen Sie ein Beispiel, das beide Alternativen zeigt ( live sehen ):
Wenn Sie die magische Variable PRETTY_FUNCTION verwenden
gcc
oderclang
wir sie verwenden können, um die Typensignatur der Funktion anzuzeigen, kann dies hilfreich sein, um zu verstehen, was vor sich geht. Zum Beispiel mit:Die folgenden Ergebnisse würden für verschiedene Funktionen im Beispiel folgen ( siehe live ):
In Visual Studio können Sie FUNCSIG verwenden .
Aktualisieren Sie Pre C ++ 11
Pre C ++ 11 die Alternative für std :: initializer_list wäre std :: vector oder einer der anderen Standardcontainer :
und die Alternative für variadische Vorlagen wären variadische Funktionen, obwohl sie nicht typsicher und im Allgemeinen fehleranfällig sind und unsicher zu verwenden sind, aber die einzige andere mögliche Alternative wäre die Verwendung von Standardargumenten , obwohl dies nur eine begrenzte Verwendung hat. Das folgende Beispiel ist eine modifizierte Version des Beispielcodes in der verknüpften Referenz:
Die Verwendung variabler Funktionen unterliegt auch Einschränkungen bei den Argumenten, die Sie übergeben können. Dies wird im Entwurf des C ++ - Standards im Abschnitt
5.2.2
Funktionsaufruf Absatz 7 beschrieben :quelle
typename
vs-class
Nutzung über absichtlich? Wenn ja, bitte erläutern.initializer_list
rekursiv zu machen ?Eine C ++ 17-Lösung: vollständige Typensicherheit + nette Aufrufsyntax
Seit der Einführung variabler Vorlagen in C ++ 11 und Fold-Ausdrücken in C ++ 17 ist es möglich, eine Vorlagenfunktion zu definieren, die am Aufruferstandort aufrufbar ist, als wäre sie eine varidische Funktion, aber mit den Vorteilen von ::
Hier ist ein Beispiel für gemischte Argumenttypen
Und eine andere mit erzwungener Typübereinstimmung für alle Argumente:
Mehr Informationen:
quelle
template<class Head, class... Tail, class = std::enable_if_t<are_same<Head, Tail...>::value, void>>
Head
undTail...
sind gleich ", wobei " sind gleich " bedeutetstd::conjunction<std::is_same<Head, Tail>...>
. Lesen Sie diese letzte Definition als "Head
ist das gleiche wie alleTail...
".In C ++ 11 können Sie Folgendes tun:
Listeninitialisierer FTW!
quelle
In C ++ 11 gibt es eine Möglichkeit, Vorlagen für variable Argumente zu erstellen, die zu einer wirklich eleganten und typsicheren Möglichkeit führen, Funktionen für variable Argumente zu verwenden. Bjarne selbst gibt ein schönes Beispiel für printf unter Verwendung von Vorlagen mit variablen Argumenten in C ++ 11FAQ .
Persönlich halte ich dies für so elegant, dass ich mich nicht einmal mit einer variablen Argumentfunktion in C ++ beschäftigen würde, bis dieser Compiler C ++ 11-Vorlagen für variable Argumente unterstützt.
quelle
,
Operator mit Fold-Ausdrücken verwenden). Ansonsten denke ich nicht.Variadische Funktionen im C-Stil werden in C ++ unterstützt.
Die meisten C ++ - Bibliotheken verwenden jedoch eine alternative Redewendung, z. B. während die
'c' printf
Funktion variable Argumente verwendet, verwendet dasc++ cout
Objekt eine<<
Überladung, die sich mit Typensicherheit und ADTs befasst (möglicherweise auf Kosten der einfachen Implementierung).quelle
std::initializer_lists
... Und dies führt bereits zu einer massiven Komplexität einer einfachen Aufgabe.Abgesehen von Varargs oder Überladung können Sie Ihre Argumente in einem std :: vector oder anderen Containern (z. B. std :: map) zusammenfassen. Etwas wie das:
Auf diese Weise erhalten Sie Typensicherheit und die logische Bedeutung dieser variadischen Argumente wird offensichtlich.
Sicherlich kann dieser Ansatz Leistungsprobleme haben, aber Sie sollten sich darüber keine Sorgen machen, es sei denn, Sie sind sicher, dass Sie den Preis nicht zahlen können. Es ist eine Art "pythonischer" Ansatz für c ++ ...
quelle
Der einzige Weg ist die Verwendung von Variablenargumenten im C-Stil, wie hier beschrieben . Beachten Sie, dass dies keine empfohlene Vorgehensweise ist, da sie nicht typsicher und fehleranfällig ist.
quelle
Es gibt keine Standardmethode für C ++, ohne auf varargs (
...
) im C-Stil zurückzugreifen .Es gibt natürlich Standardargumente, die je nach Kontext wie eine variable Anzahl von Argumenten "aussehen":
Alle vier Funktionsaufrufe werden
myfunc
mit unterschiedlicher Anzahl von Argumenten aufgerufen . Wenn keine angegeben sind, werden die Standardargumente verwendet. Beachten Sie jedoch, dass Sie nur nachfolgende Argumente weglassen können. Es gibt zum Beispiel keine Möglichkeit,i
nur wegzulassen und zu gebenj
.quelle
Möglicherweise möchten Sie Überladung oder Standardparameter - definieren Sie dieselbe Funktion mit Standardparametern:
Auf diese Weise können Sie die Methode mit einem von vier verschiedenen Aufrufen aufrufen:
... oder Sie suchen nach den v_args-Aufrufkonventionen von C.
quelle
Wenn Sie den Bereich der Anzahl der Argumente kennen, die bereitgestellt werden, können Sie immer eine Funktionsüberladung verwenden, z
und so weiter...
quelle
Beispiel für die Verwendung verschiedener Vorlagen zur Reproduktion
console.log
in JavaScript:Dateiname zB
js_console.h
:quelle
Wie andere gesagt haben, Varargs im C-Stil. Ähnliches können Sie aber auch mit Standardargumenten tun.
quelle
Es ist jetzt möglich ... mit boost any und templates In diesem Fall kann der Argumenttyp gemischt werden
quelle
Kombinieren Sie die C- und C ++ - Lösungen für die semantisch einfachste, performanteste und dynamischste Option. Wenn Sie es vermasseln, versuchen Sie etwas anderes.
Benutzer schreibt:
Semantisch sieht und fühlt sich dies genau wie eine n-Argument-Funktion an. Unter der Haube können Sie es auf die eine oder andere Weise auspacken.
quelle
Wir könnten auch eine initializer_list verwenden, wenn alle Argumente const und vom gleichen Typ sind
quelle
Einfache Version
quelle