Quel est le but de std::make_pair
?
Pourquoi ne pas simplement faire std::pair<int, char>(0, 'a')
?
Y a-t-il une différence entre les deux méthodes?
La différence est que avec std::pair
vous devez spécifier les types des deux éléments, alors que std::make_pair
créera une paire avec le type des éléments qui lui sont transmis, sans que vous ayez besoin de le dire. C’est ce que j’aurais pu rassembler de toute façon dans divers documents.
Voir cet exemple de 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>
En plus du bonus de conversion implicite, si vous n’utilisiez pas make_pair, vous deviez le faire.
one = pair<int,int>(10,20)
chaque fois que vous en avez affecté un, ce qui serait agaçant avec le temps ...
Comme @MSalters a répondu ci-dessus, vous pouvez maintenant utiliser des accolades pour le faire en C++ 11 (vérifiez ceci avec un compilateur C++ 11):
pair<int, int> p = {1, 2};
Il n'y a pas de différence entre utiliser make_pair
et en appelant explicitement le constructeur pair
avec les arguments de type spécifiés. std::make_pair
est plus pratique lorsque les types sont détaillés, car une méthode de modèle utilise une déduction de type basée sur ses paramètres. Par exemple,
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));
Il convient de noter qu'il s'agit d'un langage courant dans la programmation de modèles C++. C'est ce qu'on appelle l'idiome du générateur d'objet, vous pouvez trouver plus d'informations et un exemple de Nice ici .
Modifier Comme suggéré dans les commentaires (supprimé depuis), voici un extrait légèrement modifié du lien au cas où il se briserait.
Un générateur d'objets permet de créer des objets sans spécifier explicitement leurs types. Il est basé sur une propriété utile des modèles de fonction que les modèles ne possèdent pas: Les paramètres de type d'un modèle de fonction sont déduits automatiquement de ses paramètres réels. std::make_pair
est un exemple simple qui renvoie une instance du std::pair
modèle en fonction des paramètres réels du std::make_pair
une fonction.
template <class T, class U>
std::pair <T, U>
make_pair(T t, U u)
{
return std::pair <T, U> (t,u);
}
Les arguments de modèle de classe ne pouvaient pas être déduits du constructeur avant C++ 17
Avant C++ 17, vous ne pouviez pas écrire quelque chose comme:
std::pair p(1, 'a');
puisque cela déduirait des types de modèles à partir des arguments du constructeur.
C++ 17 rend cette syntaxe possible, et donc make_pair
redondant.
Avant C++ 17, std::make_pair
nous a permis d’écrire du code moins détaillé:
MyLongClassName1 o1();
MyLongClassName2 o2();
auto p = std::make_pair(o1, o2);
au lieu du plus verbeux:
std::pair<MyLongClassName1,MyLongClassName2> p{o1, o2};
qui répète les types, et peut être très long.
L'inférence de type fonctionne dans ce cas pré-C++ 17 car make_pair
n'est pas un constructeur.
make_pair
est essentiellement équivalent à:
template<class T1, class T2>
std::pair<T1, T2> my_make_pair(T1 t1, T2 t2) {
return std::pair<T1, T2>(t1, t2);
}
Le même concept s'applique à inserter
vs insert_iterator
.
Voir également:
Exemple minimal
Pour rendre les choses plus concrètes, nous pouvons observer le problème de manière minimale avec:
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);
}
ensuite:
g++-8 -Wall -Wextra -Wpedantic -std=c++17 main.cpp
compile joyeusement, mais:
g++-8 -Wall -Wextra -Wpedantic -std=c++14 main.cpp
échoue avec:
main.cpp: In function ‘int main()’:
main.cpp:13:13: error: missing template arguments before ‘my_class’
MyClass my_class(1);
^~~~~~~~
et nécessite à la place de travailler:
MyClass<int> my_class(1);
ou l'assistant:
auto my_class = make_my_class(1);
qui utilise une fonction régulière au lieu d'un constructeur.
Testé avec GCC 8.1.0, Ubuntu 16.04 .
make_pair crée une copie supplémentaire sur le constructeur direct. Je tape toujours mes paires pour fournir une syntaxe simple.
Cela montre la différence (exemple de 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;
}
à partir de c ++ 11, il suffit d'utiliser une initialisation uniforme pour les paires. Donc au lieu de:
std::make_pair(1, 2);
ou
std::pair<int, int>(1, 2);
juste utiliser
{1, 2};