Qual è lo scopo di std::make_pair
?
Perché non farlo std::pair<int, char>(0, 'a')
?
C'è qualche differenza tra i due metodi?
std::make_pair
è ridondante. C'è una risposta sotto che dettaglia questo.
Qual è lo scopo di std::make_pair
?
Perché non farlo std::pair<int, char>(0, 'a')
?
C'è qualche differenza tra i due metodi?
std::make_pair
è ridondante. C'è una risposta sotto che dettaglia questo.
Risposte:
La differenza è che con std::pair
te devi specificare i tipi di entrambi gli elementi, mentre std::make_pair
creerai una coppia con il tipo di elementi che gli vengono passati, senza che tu debba dirlo. Questo è quello che potrei comunque raccogliere da vari documenti.
Vedi questo esempio da 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>
A parte il bonus di conversione implicito, se non avessi usato make_pair avresti dovuto farlo
one = pair<int,int>(10,20)
ogni volta che lo assegni a uno, che sarebbe fastidioso nel tempo ...
std::make_pair
. Apparentemente è solo per comodità.
one = {10, 20}
giorno d'oggi, ma non ho un compilatore C ++ 11 a portata di mano per verificarlo.
make_pair
funziona con tipi senza nome, tra cui strutture, sindacati, lambda e altri doodle.
Come ha risposto @MSalters sopra, ora puoi usare le parentesi graffe per farlo in C ++ 11 (appena verificato con un compilatore C ++ 11):
pair<int, int> p = {1, 2};
Gli argomenti del modello di classe non possono essere dedotti dal costruttore prima di C ++ 17
Prima di C ++ 17 non si poteva scrivere qualcosa del genere:
std::pair p(1, 'a');
poiché ciò dedurrebbe i tipi di modello dagli argomenti del costruttore.
C ++ 17 rende possibile questa sintassi e quindi make_pair
ridondante.
Prima di C ++ 17, std::make_pair
ci ha permesso di scrivere un codice meno dettagliato:
MyLongClassName1 o1;
MyLongClassName2 o2;
auto p = std::make_pair(o1, o2);
invece del più dettagliato:
std::pair<MyLongClassName1,MyLongClassName2> p{o1, o2};
che ripete i tipi e può essere molto lungo.
L'inferenza del tipo funziona in quel caso pre-C ++ 17 perché make_pair
non è un costruttore.
make_pair
è sostanzialmente equivalente a:
template<class T1, class T2>
std::pair<T1, T2> my_make_pair(T1 t1, T2 t2) {
return std::pair<T1, T2>(t1, t2);
}
Lo stesso concetto vale per inserter
vsinsert_iterator
.
Guarda anche:
Esempio minimo
Per rendere le cose più concrete, possiamo osservare minimamente il problema con:
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);
}
poi:
g++-8 -Wall -Wextra -Wpedantic -std=c++17 main.cpp
si compila felicemente, ma:
g++-8 -Wall -Wextra -Wpedantic -std=c++14 main.cpp
fallisce con:
main.cpp: In function ‘int main()’:
main.cpp:13:13: error: missing template arguments before ‘my_class’
MyClass my_class(1);
^~~~~~~~
e richiede invece di funzionare:
MyClass<int> my_class(1);
o l'aiutante:
auto my_class = make_my_class(1);
che utilizza una funzione regolare anziché un costruttore.
Differenza per `std :: reference_wrapper
Questo commento lo menzionastd::make_pair
svolgestd::reference_wrapper
, mentre il costruttore non lo fa, così che è una differenza. Esempio TODO.
Testato con GCC 8.1.0, Ubuntu 16.04 .
std::make_pair
non è diventato obsoleto in C ++ 17?
make_pair
scartare i wrapper di riferimento, quindi in realtà è diverso dal CTAD.
Non vi è alcuna differenza tra l'utilizzo make_pair
e la chiamata esplicita al pair
costruttore con argomenti di tipo specificati. std::make_pair
è più conveniente quando i tipi sono dettagliati perché un metodo modello ha la deduzione del tipo in base ai parametri indicati. Per esempio,
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));
Vale la pena notare che questo è un linguaggio comune nella programmazione di modelli C ++. È noto come il linguaggio del generatore di oggetti, puoi trovare maggiori informazioni e un bell'esempio qui .
modificare Come suggerito da qualcuno nei commenti (da quando rimosso), il seguente è un estratto leggermente modificato dal collegamento in caso di interruzione.
Un generatore di oggetti consente la creazione di oggetti senza specificare esplicitamente i loro tipi. Si basa su un'utile proprietà dei modelli di funzione che i modelli di classe non hanno: I parametri di tipo di un modello di funzione vengono dedotti automaticamente dai suoi parametri effettivi. std::make_pair
è un semplice esempio che restituisce un'istanza del std::pair
modello in base ai parametri effettivi della std::make_pair
funzione.
template <class T, class U>
std::pair <T, U>
make_pair(T t, U u)
{
return std::pair <T, U> (t,u);
}
&&
dal C ++ 11.
make_pair crea una copia aggiuntiva sul costruttore diretto. Ho sempre scritto le mie coppie per fornire una sintassi semplice.
Questo mostra la differenza (esempio di 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
solo dentro insert
e / o intorno a quale sarebbe un riferimento sample
. È solo quando cambio std::map<int,Sample>
a std::map<int,Sample const&>
che riduco il numero di oggetti costruiti, e solo quando cancello il costruttore di copie che elimino tutte le copie (ovviamente). Dopo aver apportato entrambe queste modifiche, il mio risultato include una chiamata al costruttore predefinito e due chiamate al distruttore per lo stesso oggetto. Penso che mi debba mancare qualcosa. (g ++ 5.4.1, c ++ 11)
emplace
invece insert
se stai solo costruendo un valore da inserire immediatamente (e non vuoi istanze extra.) Non è la mia area di competenza, se posso anche dire di averne uno, ma la copia / sposta la semantica introdotta da C ++ 11 mi ha aiutato molto.
a partire da c ++ 11 basta usare l'inizializzazione uniforme per le coppie. Quindi invece di:
std::make_pair(1, 2);
o
std::pair<int, int>(1, 2);
basta usare
{1, 2};
{1, 2}
può essere utilizzato per inizializzare una coppia, ma non esegue il commit per la coppia di tipi. Vale a dire quando si utilizza auto è necessario impegnarsi a un tipo sul RHS: auto p = std::pair{"Tokyo"s, 9.00};
.