Sagen wir, ich habe diese Struktur:
%Vor%und eine andere Klasse, die dies als Konstruktorargument verwendet:
%Vor%Wie kann ich das einfache
bekommen? %Vor%um zu arbeiten?
Gegenwärtig versucht der Compiler, über die initializer_list<int>
übereinzustimmen und die Array-Variante von make_unique
aufzurufen, was albern ist, weil positioned
nur einen Konstruktor hat. Dasselbe Problem tritt für die Funktionen emplace
und emplace_back
auf. So ziemlich jede Funktion, die ihre variablen Template-Argumente an den Konstruktor einer Klasse weiterleitet, scheint dieses Verhalten zu zeigen.
Ich verstehe, dass ich das durch
lösen kannpositioned
einen Konstruktor mit zwei int
-Argumenten und den {}
im Aufruf von make_unique
oder make_unique
als position{1,2}
. Beide scheinen übermäßig wortreich zu sein, wie es mir scheint (mit einigem Aufwand in der make_unique-Implementierung), das kann ohne diese Überspezifizierung des Argumenttyps gelöst werden.
Ist das ein lösbarer Fehler in der make_unique
-Implementierung oder ist das ein unlösbarer, uninteressanter Edge-Case, den niemandem interessieren sollte?
Die Argumentableitung von Funktionsvorlagen funktioniert nicht, wenn eine stained-init-Liste angegeben wird. Es funktioniert nur basierend auf tatsächlichen Ausdrücken.
Es sollte auch beachtet werden, dass positioned
auf keinen Fall von {1, 2}
initialisiert werden kann. Dies wird versuchen, einen Konstruktor mit zwei Argumenten aufzurufen, und positioned
hat keinen solchen Konstruktor. Sie müssten positioned({1, 2})
oder positioned{{1, 2}}
verwenden.
Als solche wäre die allgemeine Lösung, dass make_unique
irgendwie die Signatur aller möglichen Konstruktoren für den Typ, den sie konstruiert, magisch reproduziert. Dies ist offensichtlich in C ++ zu diesem Zeitpunkt keine vernünftige Sache.
Eine Alternative wäre, ein Lambda zum Erstellen des Objekts zu verwenden und eine alternative make
-Funktion zu schreiben. Verwenden Sie die garantierten Elisionsregeln von C ++ 17, um den zurückgegebenen prvalue auf den internen new
-Ausdruck anzuwenden:
Sie können sogar den Parameter typename T
ablegen:
Soweit ich sehen kann, ist der praktischste Weg, dies zu tun, wahrscheinlich, die Klammern zu entfernen und Konstruktoren hinzuzufügen, um die Argumente diskret zu nehmen:
%Vor% Wenn position
mehr als ein ctor hatte, würden Sie wahrscheinlich eine variadic template ctor für positioned
erstellen, um einige beliebige Parameter zu übernehmen und an position
s ctor (s) weiterzuleiten.
Auf diese Weise werden die Argumente von make_unique
nach positioned
nach position
weitergeleitet. Dies bietet zumindest einen gewissen potentiellen Vorteil in der Effizienz - anstatt die Argumente zu verwenden, um ein temporäres Objekt zu erzeugen, das dann übergeben wird, um das zugrundeliegende Objekt zu initialisieren, übergibt es (Referenzen auf) die ursprünglichen Objekte direkt an das ctor für das zugrundeliegendes Objekt, also konstruieren wir es nur einmal, an Ort und Stelle.
Beachten Sie, dass dies uns eine gewisse Vielseitigkeit verleiht. Angenommen, positioned
war selbst eine Vorlage und das zugrunde liegende position
ein Vorlagenargument:
Kompatibilität: Ich glaube, das erfordert C ++ 14 oder neuer, da% make_unique
dann seine Weiterleitung / variadic ctor hat.
Das Problem ist, dass Initiatoren wie {1, 2}
nicht abgeleitet werden können: der folgende Code funktioniert nicht (aus gutem Grund: Wie ist {1, 2}
?).
make_unique
ist nur eine komplexere Variante dieses Themas.
Die Ursache wird hier im Detail erklärt: initializer_list und Vorlagentyp Abzug
Tags und Links c++ c++14 initializer-list c++17 unique-ptr