Während Mfontaninis Lösung funktioniert und gut ist, weil sie die Berechnung des inkrementierenden Spaltenindex zur Kompilierzeit durchführt, denke ich, es lohnt sich, darauf hinzuweisen, dass es auch eine direkte Antwort auf Frage von gibt, wie man ein int in einem variadic erhöht Packexpansion. (Leider scheint es bei GCC aufgrund eines Fehlers nicht zu funktionieren, siehe den Vorbehalt am Ende.)
Die Antwort basiert auf der Tatsache, dass während die Auswertungen von Argumenten in einem Funktionsaufruf unsequenced sind, die Auswertungen von Argumente in einer Liste Initialisierung nicht sind:
(§8.5.4/4) innerhalb der Initialisierer-Liste einer verspannten-init-Liste, die Initialisierer-Klauseln, einschließlich aller, die aus Packungsdehnungen führen (14.5.3), werden in der Reihenfolge ausgewertet, in der sie erscheinen. Das heißt, jede Wertberechnung und jeder Nebeneffekt, der einer gegebenen Initialisierungsklausel zugeordnet ist, wird vor jeder Wertberechnung und jedem Nebeneffekt, der mit einer Initialisierungsklausel verknüpft ist, die ihr folgt, in der kommagetrennten Liste der Initialisierungsliste sequenziert.
[Hinweis: Diese Reihenfolge der Auswertung gilt unabhängig von der Semantik der Initialisierung; zum Beispiel gilt es, wenn die Elemente der Initialisiererliste als Argumente eines Konstruktoraufrufs interpretiert werden, obwohl normalerweise keine Sequenzbeschränkungen für die Argumente eines Aufrufs bestehen. - Endnote]
Deshalb, wenn Sie Ihren Funktionsaufruf in etwas verwandeln, basierend auf einer Doppelpack-init-Liste, werden Sie den gewünschten Effekt erhalten:
rowCallback(std::tuple<ColumnTypes...> { getColumn<ColumnTypes>(column++)... });
Dieses initialisiert eine std::tuple
mit Liste -Initialisierung (beachten Sie die geschweiften Klammern { ... }
), daher wird die column++
Nebeneffekt in der Reihenfolge von links nach rechts durchgeführt werden.
Wenn oben beschrieben, bedeutet dies, dass Sie rowCallback()
ändern müssen, damit es eine std::tuple
statt einer Liste von Argumenten akzeptiert. Wenn Sie das nicht mögen, können Sie eine separate Template-Funktion call_on_tuple(fun,tup)
erstellen, die jede Funktion fun
für die Argumente aufruft, die sich aus dem expandierenden Tupel tup
ergeben. Ich habe einmal beschrieben, wie man das macht here, oder wenn Sie möchten, könnten Sie rlxutil::call_on_tuple
von my GitHub repository verwenden.
Ihre execute
Funktion sieht dann wie folgt aus:
template <typename... ColumnTypes>
void execute(function<void(ColumnTypes...)> rowCallback)
{
using std::tuple;
using rlxutil::call_on_tuple;
int column = 0;
call_on_tuple(rowCallback,
tuple<ColumnTypes...> { getColumn<ColumnTypes>(column++)... });
}
Caveat: Das ist wie mit GCC erwartet funktioniert nicht. Ich glaube, das liegt an dem hier gemeldeten Fehler: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51253.
Sie setzen die Spalte jedes Mal auf Null. – jthill
@jthill: Korrigieren, in jeder Zeile starte ich von Spalte Null neu, wenn die Werte aus der Zeile extrahiert werden. –
Warum nicht eine einfache Funktion erstellen, die eine Referenz aufnimmt, diese Referenz inkrementiert und den alten Wert zurückgibt? –