Was ist der Zweck von std::make_pair?
Warum nicht einfach tun std::pair<int, char>(0, 'a')?
Gibt es einen Unterschied zwischen den beiden Methoden?
std::make_pairist redundant. Es gibt eine Antwort unten, die dies detailliert beschreibt.
Was ist der Zweck von std::make_pair?
Warum nicht einfach tun std::pair<int, char>(0, 'a')?
Gibt es einen Unterschied zwischen den beiden Methoden?
std::make_pairist redundant. Es gibt eine Antwort unten, die dies detailliert beschreibt.
Antworten:
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.
Siehe dieses Beispiel unter http://www.cplusplus.com/reference/std/utility/make_pair/
pair <int,int> one;
pair <int,int> two;
one = make_pair (10,20);
two = make_pair (10.5,'A'); // ok: implicit conversion from pair<double,char>
Abgesehen vom impliziten Conversion-Bonus müssten Sie dies tun, wenn Sie make_pair nicht verwenden würden
one = pair<int,int>(10,20)
jedes Mal, wenn Sie einem zugewiesen haben, was mit der Zeit ärgerlich wäre ...
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_pairmit 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):
pair<int, int> p = {1, 2};
Klassenvorlagenargumente konnten vor C ++ 17 nicht vom Konstruktor abgeleitet werden
Vor C ++ 17 konnte man so etwas nicht schreiben:
std::pair p(1, 'a');
da dies Vorlagentypen aus den Konstruktorargumenten ableiten würde.
C ++ 17 macht diese Syntax möglich und daher make_pairredundant.
Vor C ++ 17 std::make_pairdurften wir weniger ausführlichen Code schreiben:
MyLongClassName1 o1;
MyLongClassName2 o2;
auto p = std::make_pair(o1, o2);
statt der ausführlicheren:
std::pair<MyLongClassName1,MyLongClassName2> p{o1, o2};
Das wiederholt die Typen und kann sehr lang sein.
Die Typinferenz funktioniert in diesem Fall vor C ++ 17, da make_paires sich nicht um einen Konstruktor handelt.
make_pair ist im Wesentlichen gleichbedeutend mit:
template<class T1, class T2>
std::pair<T1, T2> my_make_pair(T1 t1, T2 t2) {
return std::pair<T1, T2>(t1, t2);
}
Das gleiche Konzept gilt für insertervs insert_iterator.
Siehe auch:
Minimales Beispiel
Um die Dinge konkreter zu machen, können wir das Problem minimal beobachten mit:
main.cpp
template <class MyType>
struct MyClass {
MyType i;
MyClass(MyType i) : i(i) {}
};
template<class MyType>
MyClass<MyType> make_my_class(MyType i) {
return MyClass<MyType>(i);
}
int main() {
MyClass<int> my_class(1);
}
dann:
g++-8 -Wall -Wextra -Wpedantic -std=c++17 main.cpp
kompiliert gerne, aber:
g++-8 -Wall -Wextra -Wpedantic -std=c++14 main.cpp
schlägt fehl mit:
main.cpp: In function ‘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.
Getestet mit GCC 8.1.0, Ubuntu 16.04 .
std::make_pairin C ++ 17 nicht veraltet?
make_pairpackt Referenz-Wrapper aus, unterscheidet sich also tatsächlich von CTAD.
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,
std::vector< std::pair< std::vector<int>, std::vector<int> > > vecOfPair;
std::vector<int> emptyV;
// shorter
vecOfPair.push_back(std::make_pair(emptyV, emptyV));
// longer
vecOfPair.push_back(std::pair< std::vector<int>, std::vector<int> >(emptyV, emptyV));
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 .
template <class T, class U>
std::pair <T, U>
make_pair(T t, U u)
{
return std::pair <T, U> (t,u);
}
&&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):
class Sample
{
static int _noOfObjects;
int _objectNo;
public:
Sample() :
_objectNo( _noOfObjects++ )
{
std::cout<<"Inside default constructor of object "<<_objectNo<<std::endl;
}
Sample( const Sample& sample) :
_objectNo( _noOfObjects++ )
{
std::cout<<"Inside copy constructor of object "<<_objectNo<<std::endl;
}
~Sample()
{
std::cout<<"Destroying object "<<_objectNo<<std::endl;
}
};
int Sample::_noOfObjects = 0;
int main(int argc, char* argv[])
{
Sample sample;
std::map<int,Sample> map;
map.insert( std::make_pair( 1, sample) );
//map.insert( std::pair<int,Sample>( 1, sample) );
return 0;
}
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)
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.
Verwenden Sie ab C ++ 11 nur eine einheitliche Initialisierung für Paare. Also statt:
std::make_pair(1, 2);
oder
std::pair<int, int>(1, 2);
benutz einfach
{1, 2};
{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};.