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_pair
ist 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_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ährend std::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/
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_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):
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_pair
redundant.
Vor C ++ 17 std::make_pair
durften 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_pair
es 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 inserter
vs 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_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 .
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 des pair
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,
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_pair
ist ein einfaches Beispiel, das std::pair
abhängig von den tatsächlichen Parametern der std::make_pair
Funktion 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::move
nur innerhalb insert
und / 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)
emplace
anstatt insert
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:
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};
.