Seite 1 von 1

variadic template vs. initializer_list

Verfasst: 30.05.2022, 12:47
von Jonathan
Moin,

angenommen ich habe eine Funktion mit einer variablen Menge an Parametern, also etwa

Code: Alles auswählen

Mesh join(Mesh& m1, Mesh& m2, ... Mesh& mn);
Wie implementiert man das am nettesten?

Meine erster Gedanke waren variadic-templates. Die sind aber grässlich zu schreiben und zu lesen, alleine schon weil man immer mindestens 2 Funktionen braucht. Die zweite Idee ist, einen Container an Meshs zu übergeben und mir scheint, dass sich da eine initializer_list am ehesten anbiete. Die macht zum einen die Implementierung kompakt und übersichtlich (eine for-loop über alle Elemente) und zum anderen ist das Interface auch recht nett (verglichen mit z.B. verschachtelten Aufrufen einer Funktion die jeweils 2 Meshs kombiniert).

Aber wie sieht das ganze Performance technisch aus? Ist initializer_list so light-weight wie es wird? Ich vermute mal, dass es zumindest besser (oder halt gleich) als alle anderen Container (vector z.B.) ist. Aber verglichen mit variadic templates schätze ich, , dass es ein Problem sein könnte, dass die Funktion nur einmal kompiliert wird. Wenn man nur 2 oder 3 Meshs kombinieren will hat man trotzdem den Overhead von der Schleife. Oder könnte der Kompilier hier irgendeine Chance haben etwas zu optimieren? Andererseits sollte der Overhead zumindest in diesem Fall eigentlich minimal sein, da die Funktion hier tatsächlich alle Vertices kopieren soll.

Was sind eure Meinungen / best practises zum Thema 'variable Argumente'?

Re: variadic template vs. initializer_list

Verfasst: 30.05.2022, 13:01
von Lord Delvin
Mir ist nicht ganz klar, was du mit kombinieren meinst und wie viele unterschiedliche Verwendungen es im Code geben kann. Auch ist mir nicht ganz klar, wie performancekritisch das jetzt wirklich ist.
Hätte jetzt mal Array/std::vector oder C varargs vorgeschlagen. Kommt ein bisschen drauf an. Wenn du das einmal für zwei und einmal drei Parameter verwendest kannst du dir auch überlegen, einfach beide Funktionen hinzuschreiben und auf die Abstraktion zu pfeifen.

Re: variadic template vs. initializer_list

Verfasst: 30.05.2022, 13:13
von Jonathan
Ich merke gerade, dass initializer_list wohl nicht mit Referenzen funktioniert, sondern dass ich in diesem Fall Zeiger verwenden muss.

So wie ich das sehe habe ich also:
- Variadic template: Referenzen (also Zeiger) werden als Argumente auf den Stack kopiert.
- Initializer_list: Zeiger werden in ein Array kopiert, das Array (Anfangs- und Endzeiger) werden als Argumente auf den Stack kopiert.

Die initializer_list hat also eine Indirektion und eine Handvoll Argumente mehr, verglichen mit dem template. Das ist wohl nicht kritisch, aber dennoch find ich es ernüchternd dass die Variante die schön zu programmieren ist doch signifikante Mehrkosten hat. Es sollte doch eigentlich nicht so schwer sein variable Argumente schön UND effizient zu unterstützen...

Re: variadic template vs. initializer_list

Verfasst: 30.05.2022, 13:19
von Jonathan
Lord Delvin hat geschrieben: 30.05.2022, 13:01 Mir ist nicht ganz klar, was du mit kombinieren meinst und wie viele unterschiedliche Verwendungen es im Code geben kann. Auch ist mir nicht ganz klar, wie performancekritisch das jetzt wirklich ist.
Hätte jetzt mal Array/std::vector oder C varargs vorgeschlagen. Kommt ein bisschen drauf an. Wenn du das einmal für zwei und einmal drei Parameter verwendest kannst du dir auch überlegen, einfach beide Funktionen hinzuschreiben und auf die Abstraktion zu pfeifen.
Mal als Pseudo-Code:

Code: Alles auswählen

Mesh joind(vector<Mesh> meshes)
{
   Mesh result;
   for(auto m : meshes)
   {
     result.vertices.append(m.vertices);
     result.indices.append(m.indices);
   }
   return result;
}
Anwendungsfall ist prozedurale Geometrie, ein bisschen Richtung Geometry-Nodes in Blender. D.h. man wird vermutlich meistens nur 2 oder 3 Meshes kombinieren wollen, aber halt theoretisch auch mal mehr.

Aber die vargs hatte ich ganz vergessen, vielleicht ist das tatsächlich die beste Lösung in diesem Fall. Ich schau mir die mal genauer an.

Re: variadic template vs. initializer_list

Verfasst: 30.05.2022, 13:34
von Schrompf
C-Style-Varargs brauchen dann ja auch Pointer. Die initializer_list ist bei der Aufgerufenen ne Runtime-große Liste. Aber "join meshes" klingt für mich eh rechenzeitaufwändig, da ist der Overhead einer dynamisch großen Liste irrelevant. Nimm std::span, wenn Du kannst :-)

Re: variadic template vs. initializer_list

Verfasst: 30.05.2022, 14:39
von Lord Delvin
Mit der Erklärung würde ich mich Schrompf anschließen.
Von sowas wie Templates würde ich in dem Fall auch abraten, da sie zu viel Code generieren und du davon in dem Fall nichts hast.

Re: variadic template vs. initializer_list

Verfasst: 30.05.2022, 16:45
von Alexander Kornrumpf
Jonathan hat geschrieben: 30.05.2022, 12:47 Was sind eure Meinungen / best practises zum Thema 'variable Argumente'?
Ketzerisch bzw. polemisch, dass das nur in den Sprachen drin ist, damit sie printf/Format-Strings implementieren können und dass ich noch keinen anderen Anwendungsfall gefunden habe.

Ich habe hier eine Codebase (nicht C++) wo irgendjemand wohlmeinend beliebige Parameter in Kontexten ähnlich deines Beispiels implementiert hat und - bei näherem Nachdenken mMn wenig überraschend - fallen die Aufrufe alle in eine der drei Fälle {eins, zwei, der Aufrufer müsste schon ein Array haben}. Also das jetzt methodenübergreifend, für einzelne Methoden sind zwei dieser drei Aufruferklassen [nicht im OOP Sinn gemeint] oft leer was es nur noch lustiger macht. Ich refactor die variable Parameterliste dann immer weg denn diese maximal drei Fälle kann ich besser (lesbarer, übersichtlicher, schneller) von Hand abarbeiten.

Das Gimmick bei Formatstrings ist ja gerade, dass sie verschiedenartige Objekte [nicht im OOP Sinn gemeint] zusammensticken können und sollen. Wenn du mehr als zwei gleichartige Objekte hast, und die einzeln auflisten willst, machst du mMn was falsch.