In C ++ 11 können Sie fast vollständig auf make_pair verzichten. Siehe meine Antwort .
PlagueHammer
2
In C ++ 17 std::make_pairist redundant. Es gibt eine Antwort unten, die dies detailliert beschreibt.
Drew Dormann
Antworten:
165
Der Unterschied besteht darin, dass std::pairSie die Typen beider Elemente angeben müssen, während std::make_pairein Paar mit dem Typ der Elemente erstellt wird, die an das Element übergeben werden, ohne dass Sie es angeben müssen. Das könnte ich sowieso aus verschiedenen Dokumenten entnehmen.
Tatsächlich sollten die Typen zur Kompilierungszeit abgeleitet werden, ohne dass eine Angabe erforderlich ist.
Tschad
@Tor Ja, ich weiß, wie man beide benutzt, ich war nur neugierig, ob es einen Grund dafür gibt std::make_pair. Anscheinend ist es nur zur Vereinfachung.
@ Jay Es scheint so.
Tor Valamo
15
Ich denke, Sie können dies one = {10, 20}heutzutage tun , aber ich habe keinen C ++ 11-Compiler zur Hand, um dies zu überprüfen.
MSalters
6
Beachten Sie auch, dass dies make_pairmit unbenannten Typen funktioniert, einschließlich Strukturen, Gewerkschaften, Lambdas und anderen Doodads.
Mooing Duck
35
Wie @MSalters oben geantwortet hat, können Sie jetzt in C ++ 11 geschweifte Klammern verwenden (dies wurde gerade mit einem C ++ 11-Compiler überprüft):
main.cpp:Infunction‘int main()’:
main.cpp:13:13: error: missing template arguments before ‘my_class’MyClass my_class(1);^~~~~~~~
und erfordert stattdessen zu arbeiten:
MyClass<int> my_class(1);
oder der Helfer:
auto my_class = make_my_class(1);
die eine reguläre Funktion anstelle eines Konstruktors verwendet.
Unterschied für `std :: reference_wrapper
In diesem Kommentar wird erwähnt, dass das std::make_pairEntpacken erfolgt, std::reference_wrapperwährend der Konstruktor dies nicht tut. Das ist also ein Unterschied. TODO Beispiel.
"C ++ 17 macht diese Syntax möglich und macht make_pair daher redundant." - Warum ist es std::make_pairin C ++ 17 nicht veraltet?
Andreee
@andreee Ich bin mir nicht sicher, möglicher Grund ist, dass es keine Probleme verursacht, also keine Notwendigkeit, alten Code zu brechen? Aber ich bin nicht mit den Gründen des C ++ - Komitees vertraut. Pingen Sie mich an, wenn Sie etwas finden.
Ciro Santilli 6 冠状 病 六四.
1
Eine nützliche Sache, auf die ich gestoßen bin, ist, dass die Möglichkeit, die Typen mit std :: make_pair <T1, T2> (o1, o2) anzugeben, den Benutzer daran hindert, den Fehler zu machen, die Typen o1 oder o2 zu übergeben, die nicht implizit sein können auf T1 oder T2 werfen. Zum Beispiel eine negative Zahl an ein vorzeichenloses int übergeben. -Wsign-convert -Werror fängt diesen Fehler mit dem Konstruktor std :: pair in c ++ 11 nicht ab, fängt jedoch den Fehler ab, wenn std :: make_pair verwendet wird.
Conchoecia
make_pairpackt Referenz-Wrapper aus, unterscheidet sich also tatsächlich von CTAD.
LF
26
Es gibt keinen Unterschied zwischen der Verwendung make_pairund dem expliziten Aufruf des pairKonstruktors mit angegebenen Typargumenten. std::make_pairDies ist praktischer, wenn die Typen ausführlich sind, da eine Vorlagenmethode eine Typableitung basierend auf den angegebenen Parametern aufweist. Beispielsweise,
Es ist erwähnenswert, dass dies eine gängige Redewendung in der C ++ - Vorlagenprogrammierung ist. Es ist als Objektgenerator-Sprache bekannt. Weitere Informationen und ein schönes Beispiel finden Sie hier .
Bearbeiten Wie in den Kommentaren vorgeschlagen (seitdem entfernt), ist das Folgende ein leicht modifizierter Auszug aus dem Link, falls er kaputt geht.
Ein Objektgenerator ermöglicht die Erstellung von Objekten, ohne deren Typ explizit anzugeben. Es basiert auf einer nützlichen Eigenschaft von Funktionsvorlagen, die Klassenvorlagen nicht haben: Die Typparameter einer Funktionsvorlage werden automatisch aus ihren tatsächlichen Parametern abgeleitet. std::make_pairist ein einfaches Beispiel, das std::pairabhängig von den tatsächlichen Parametern der std::make_pairFunktion eine Instanz der Vorlage zurückgibt .
make_pair erstellt eine zusätzliche Kopie über den direkten Konstruktor. Ich tippe meine Paare immer ein, um eine einfache Syntax bereitzustellen.
Dies zeigt den Unterschied (Beispiel von Rampal Chaudhary):
Ich bin mir ziemlich sicher, dass die zusätzliche Kopie in allen Fällen entfernt wird, wenn die Optimierungseinstellungen des Compilers hoch genug sind.
Björn Pollex
1
Warum sollten Sie sich jemals auf Compiler-Optimierungen verlassen wollen, um die Richtigkeit zu gewährleisten?
sjbx
Ich erhalte die gleichen Ergebnisse mit beiden Versionen und mit std::movenur innerhalb insertund / oder um das, worauf ein Verweis wäre sample. Es ist nur , wenn ich ändern std::map<int,Sample>zu , std::map<int,Sample const&>dass ich die Anzahl der konstruierten Objekte zu reduzieren, und nur , wenn ich den Copykonstruktor löschen , dass ich alle Kopien beseitigen (offensichtlich). Nachdem ich diese beiden Änderungen vorgenommen habe, enthält mein Ergebnis einen Aufruf des Standardkonstruktors und zwei Aufrufe des Destruktors für dasselbe Objekt. Ich denke, ich muss etwas vermissen. (g ++ 5.4.1, c ++ 11)
John P
FWIW Ich stimme zu, dass Optimierung und Korrektheit völlig unabhängig sein sollten, da dies genau die Art von Code ist, die Sie als Überprüfung der Integrität schreiben, nachdem verschiedene Optimierungsstufen zu inkonsistenten Ergebnissen führen. Im Allgemeinen würde ich empfehlen, emplaceanstatt insertnur einen Wert zu erstellen, der sofort eingefügt werden soll (und Sie möchten keine zusätzlichen Instanzen). Es ist nicht mein Fachgebiet, wenn ich überhaupt sagen kann, dass ich einen habe, sondern das Kopieren / Verschieben Die von C ++ 11 eingeführte Semantik hat mir sehr geholfen.
John P
Ich glaube, ich habe genau das gleiche Problem und nachdem ich den ganzen Abend über debuggt hatte, kam ich endlich hierher.
lllllllllllll
1
Verwenden Sie ab C ++ 11 nur eine einheitliche Initialisierung für Paare. Also statt:
{1, 2}kann zum Initialisieren eines Paares verwendet werden, wird jedoch nicht für ein Typpaar festgeschrieben. Das heißt, wenn Sie auto verwenden, müssen Sie sich auf einen Typ auf der rechten Seite festlegen : auto p = std::pair{"Tokyo"s, 9.00};.
std::make_pair
ist redundant. Es gibt eine Antwort unten, die dies detailliert beschreibt.Antworten:
Der Unterschied besteht darin, dass
std::pair
Sie die Typen beider Elemente angeben müssen, währendstd::make_pair
ein Paar mit dem Typ der Elemente erstellt wird, die an das Element übergeben werden, ohne dass Sie es angeben müssen. Das könnte ich sowieso aus verschiedenen Dokumenten entnehmen.Siehe dieses Beispiel unter http://www.cplusplus.com/reference/std/utility/make_pair/
Abgesehen vom impliziten Conversion-Bonus müssten Sie dies tun, wenn Sie make_pair nicht verwenden würden
jedes Mal, wenn Sie einem zugewiesen haben, was mit der Zeit ärgerlich wäre ...
quelle
std::make_pair
. Anscheinend ist es nur zur Vereinfachung.one = {10, 20}
heutzutage tun , aber ich habe keinen C ++ 11-Compiler zur Hand, um dies zu überprüfen.make_pair
mit unbenannten Typen funktioniert, einschließlich Strukturen, Gewerkschaften, Lambdas und anderen Doodads.Wie @MSalters oben geantwortet hat, können Sie jetzt in C ++ 11 geschweifte Klammern verwenden (dies wurde gerade mit einem C ++ 11-Compiler überprüft):
quelle
Klassenvorlagenargumente konnten vor C ++ 17 nicht vom Konstruktor abgeleitet werden
Vor C ++ 17 konnte man so etwas nicht schreiben:
da dies Vorlagentypen aus den Konstruktorargumenten ableiten würde.
C ++ 17 macht diese Syntax möglich und daher
make_pair
redundant.Vor C ++ 17
std::make_pair
durften wir weniger ausführlichen Code schreiben:statt der ausführlicheren:
Das wiederholt die Typen und kann sehr lang sein.
Die Typinferenz funktioniert in diesem Fall vor C ++ 17, da
make_pair
es sich nicht um einen Konstruktor handelt.make_pair
ist im Wesentlichen gleichbedeutend mit:Das gleiche Konzept gilt für
inserter
vsinsert_iterator
.Siehe auch:
Minimales Beispiel
Um die Dinge konkreter zu machen, können wir das Problem minimal beobachten mit:
main.cpp
dann:
kompiliert gerne, aber:
schlägt fehl mit:
und erfordert stattdessen zu arbeiten:
oder der Helfer:
die eine reguläre Funktion anstelle eines Konstruktors verwendet.
Unterschied für `std :: reference_wrapper
In diesem Kommentar wird erwähnt, dass das
std::make_pair
Entpacken erfolgt,std::reference_wrapper
während der Konstruktor dies nicht tut. Das ist also ein Unterschied. TODO Beispiel.Getestet mit GCC 8.1.0, Ubuntu 16.04 .
quelle
std::make_pair
in C ++ 17 nicht veraltet?make_pair
packt Referenz-Wrapper aus, unterscheidet sich also tatsächlich von CTAD.Es gibt keinen Unterschied zwischen der Verwendung
make_pair
und dem expliziten Aufruf despair
Konstruktors mit angegebenen Typargumenten.std::make_pair
Dies ist praktischer, wenn die Typen ausführlich sind, da eine Vorlagenmethode eine Typableitung basierend auf den angegebenen Parametern aufweist. Beispielsweise,quelle
Es ist erwähnenswert, dass dies eine gängige Redewendung in der C ++ - Vorlagenprogrammierung ist. Es ist als Objektgenerator-Sprache bekannt. Weitere Informationen und ein schönes Beispiel finden Sie hier .
Bearbeiten Wie in den Kommentaren vorgeschlagen (seitdem entfernt), ist das Folgende ein leicht modifizierter Auszug aus dem Link, falls er kaputt geht.
Ein Objektgenerator ermöglicht die Erstellung von Objekten, ohne deren Typ explizit anzugeben. Es basiert auf einer nützlichen Eigenschaft von Funktionsvorlagen, die Klassenvorlagen nicht haben: Die Typparameter einer Funktionsvorlage werden automatisch aus ihren tatsächlichen Parametern abgeleitet.
std::make_pair
ist ein einfaches Beispiel, dasstd::pair
abhängig von den tatsächlichen Parametern derstd::make_pair
Funktion eine Instanz der Vorlage zurückgibt .quelle
&&
seit C ++ 11.make_pair erstellt eine zusätzliche Kopie über den direkten Konstruktor. Ich tippe meine Paare immer ein, um eine einfache Syntax bereitzustellen.
Dies zeigt den Unterschied (Beispiel von Rampal Chaudhary):
quelle
std::move
nur innerhalbinsert
und / oder um das, worauf ein Verweis wäresample
. Es ist nur , wenn ich ändernstd::map<int,Sample>
zu ,std::map<int,Sample const&>
dass ich die Anzahl der konstruierten Objekte zu reduzieren, und nur , wenn ich den Copykonstruktor löschen , dass ich alle Kopien beseitigen (offensichtlich). Nachdem ich diese beiden Änderungen vorgenommen habe, enthält mein Ergebnis einen Aufruf des Standardkonstruktors und zwei Aufrufe des Destruktors für dasselbe Objekt. Ich denke, ich muss etwas vermissen. (g ++ 5.4.1, c ++ 11)emplace
anstattinsert
nur einen Wert zu erstellen, der sofort eingefügt werden soll (und Sie möchten keine zusätzlichen Instanzen). Es ist nicht mein Fachgebiet, wenn ich überhaupt sagen kann, dass ich einen habe, sondern das Kopieren / Verschieben Die von C ++ 11 eingeführte Semantik hat mir sehr geholfen.Verwenden Sie ab C ++ 11 nur eine einheitliche Initialisierung für Paare. Also statt:
oder
benutz einfach
quelle
{1, 2}
kann zum Initialisieren eines Paares verwendet werden, wird jedoch nicht für ein Typpaar festgeschrieben. Das heißt, wenn Sie auto verwenden, müssen Sie sich auf einen Typ auf der rechten Seite festlegen :auto p = std::pair{"Tokyo"s, 9.00};
.