Die Antwort ist NEIN, das können Sie nicht.
Ein Objekt vom Typ std::initializer_list<T>
ist ein leichtgewichtiges Proxy-Objekt, das Zugriff auf ein Array von Objekten des Typs T bietet. A std::initializer_list
Objekt wird automatisch konstruiert Wann:
- Eine geklammerte Init-Liste wird bei der Listeninitialisierung verwendet, einschließlich der Initialisierung von Funktionsaufruflisten und Zuweisungsausdrücken (nicht zu verwechseln mit Konstruktor-Initialisierungslisten)
- Eine geklammerte Init-Liste ist an Auto gebunden, auch in einer Ranged-For-Schleife
Soweit Bibliotheksunterstützung geht, std::initializer_list
hat nur einen Standardkonstruktor, der eine leere Liste erstellt, und seine Iteratoren sind konstant . Das Fehlen eines push_back()
Mitglied bedeutet, dass Sie sich z. ein std::copy
mit einem std::back_inserter
Iterator-Adapter, um es zu füllen, und Sie können auch nicht direkt über solche Iteratoren zuweisen:
#include <algorithm>
#include <initializer_list>
#include <iterator>
#include <vector>
int main()
{
auto v = std::vector<int> { 1, 2 };
std::initializer_list<int> i;
auto it = std::begin(i);
*it = begin(v); // error: read-only variable is not assignable
}
Live-Beispiel
Wenn Sie sich die Standardcontainer ansehen, akzeptieren Sie zusätzlich std::initializer_list
In ihren Konstruktoren/Insertern haben sie alle Konstruktoren/Inserter, die ein Iteratorpaar verwenden, und die Implementierung delegiert wahrscheinlich den initializer_list
Funktion zur entsprechenden Iteratorpaarfunktion. Z.B. die std::vector<T>::insert
Funktion in libc++ ist dieser einfache Einzeiler:
iterator insert(const_iterator __position, initializer_list<value_type> __il)
{return insert(__position, __il.begin(), __il.end());}
Sie sollten Ihren Code in ähnlicher Weise ändern:
void someThing(std::initializer_list<int> items)
{
someThing(items.begin(), items.end()); // delegate
}
template<class It>
void someThing(It first, It last)
{
for (auto it = first, it != last; ++it) // do your thing
}
In Zeiten, in denen Sie Ihre Artikel in einem Vektor statt in einer wörtlichen Liste haben:
std::vector<int> v = { 1, 2 };
auto i = { 1, 2 };
someThing(begin(v), end(v)); // OK
someThing(i); // also OK
someThing({1, 2}); // even better
Anscheinend nein, das ist nicht möglich. Es gibt keinen solchen Konstruktor (und ich glaube aus guten Gründen), std::initializer_list
ist eine seltsame Kreatur.
Was Sie stattdessen tun könnten, ist, someThing()
zu ändern um ein Paar Iteratoren zu akzeptieren. Auf diese Weise erhalten Sie, was Sie wollen, vorausgesetzt, Sie können die Signatur dieser Funktion ändern (sie befindet sich nicht in einer Bibliothek eines Drittanbieters usw.).
Ja, Sie können das tun, aber Sie wollen es nicht tun, denn wie Sie es tun müssen, ist ziemlich albern.
Bestimmen Sie zunächst die maximale Länge Ihrer Liste. Es muss eine maximale Länge geben, da size_t
ist nicht unbegrenzt. Finden Sie idealerweise einen besseren (kleineren) wie 10.
Schreiben Sie zweitens Magic-Switch-Code, der eine Laufzeit-Ganzzahl nimmt und sie einer Kompilierzeit-Ganzzahl zuordnet und dann eine Vorlagenklasse oder -funktion mit dieser Kompilierzeit-Ganzzahl aufruft. Solcher Code benötigt eine maximale Ganzzahlgröße -- verwenden Sie die maximale Länge oben.
Schalten Sie nun die Größe des Vektors auf magische Weise in eine Kompilierzeitlänge um.
Erstellen Sie aus 0
eine Kompilierzeitfolge von Ganzzahlen bis length-1
. Entpacken Sie diese Sequenz in initializer_list
Konstruktion, wobei jedes Mal []
aufgerufen wird auf der std::vector
. Rufen Sie Ihre Funktion mit diesem resultierenden initializer_list
auf .
Das Obige ist knifflig und lächerlich, und die meisten Compiler werden es in die Luft jagen. Es gibt einen Schritt, bei dem ich mir nicht sicher bin, ob er legal ist – der Aufbau eines initializer_list
ein legaler Ort zum Entpacken von Varardic-Argumenten?
Hier ist ein Beispiel für einen magischen Schalter:Kann ich Erstellungs- und Verwendungsorte von Strategien zur Kompilierzeit trennen?
Hier ist ein Beispiel für den Indizes- oder Sequenztrick:Konstruktorargumente aus Tupel
Dieser Beitrag sollte nur von theoretischem Interesse sein, denn praktisch ist dies eine wirklich dumme Art, dieses Problem zu lösen.
Es ist schwieriger, dies mit einem beliebigen Iterable zu tun, ohne n^2 Arbeit zu leisten. Aber da das Obige bereits lächerlich genug ist und die beliebig iterierbare Version noch lächerlicher wäre ... (Vielleicht mit einem Paket von Lambdas - es könnte schwierig sein, es so hinzubekommen, dass die Argumente der Reihe nach ausgewertet werden. Gibt es einen Sequenzpunkt dazwischen die Auswertung der verschiedenen Argumente einer Initialisierungsliste?)