Was ist der Zweck von std::make_pair
?
Warum nicht einfach std::pair<int, char>(0, 'a')
?
Gibt es einen Unterschied zwischen den beiden Methoden?
Der Unterschied ist, dass mit std::pair
Sie müssen die Typen beider Elemente angeben, während std::make_pair
erstellt ein Paar mit dem Typ der Elemente, die an es übergeben werden, ohne dass Sie es mitteilen müssen. Das ist es, was ich sowieso aus verschiedenen Dokumenten sammeln konnte.
Siehe dieses Beispiel aus 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 von dem 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 eine zugewiesen haben, was im Laufe der Zeit ärgerlich wäre ...
Wie @MSalters oben geantwortet hat, können Sie dies jetzt in C++ 11 mit geschweiften Klammern tun (dies wurde gerade mit einem C++ 11-Compiler überprüft):
pair<int, int> p = {1, 2};
Es gibt keinen Unterschied zwischen der Verwendung von make_pair
und den Konstruktor pair
mit den angegebenen Typargumenten explizit aufrufen. std::make_pair
ist praktischer, wenn die Typen ausführlich sind, da bei einer Vorlagenmethode die Typableitung auf den angegebenen Parametern basiert. 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 gebräuchliche Redewendung in der C++ - Vorlagenprogrammierung ist. Es ist als Objektgenerator-Idiom bekannt. Weitere Informationen und ein gutes Beispiel finden Sie hier .
Bearbeiten Wie jemand in den Kommentaren vorgeschlagen hat (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 Funktionsschablonen, die Klassenschablonen nicht haben: Die Typparameter einer Funktionsschablone werden automatisch aus ihren tatsächlichen Parametern abgeleitet. std::make_pair
Ist ein einfaches Beispiel, das eine Instanz der Vorlage std::pair
Abhängig von den tatsächlichen Parametern der Funktion std::make_pair
Zurückgibt.
template <class T, class U>
std::pair <T, U>
make_pair(T t, U u)
{
return std::pair <T, U> (t,u);
}
Klassenvorlagenargumente konnten vor C++ 17 nicht aus dem 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 wurde std::make_pair
erlaubte uns, weniger ausführlichen Code zu 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.
Typinferenz funktioniert in diesem Fall vor C++ 17, weil make_pair
ist kein Konstruktor.
make_pair
entspricht im Wesentlichen:
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
scheitert 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.
Getestet mit GCC 8.1.0, Ubuntu 16.04 .
make_pair erstellt eine zusätzliche Kopie über den direkten Konstruktor. Ich habe meine Paare immer eingegeben, um eine einfache Syntax zu gewährleisten.
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;
}
verwenden Sie ab c ++ 11 nur die einheitliche Initialisierung für Paare. Also statt:
std::make_pair(1, 2);
oder
std::pair<int, int>(1, 2);
benutz einfach
{1, 2};