Quel est l'objectif de std::make_pair
?
Pourquoi ne pas simplement faire std::pair(0, 'a')
?
Y a-t-il une différence entre les deux méthodes?
Quel est l'objectif de std::make_pair
?
Pourquoi ne pas simplement faire std::pair(0, 'a')
?
Y a-t-il une différence entre les deux méthodes?
(Cette réponse est uniquement valable pour les normes C++14 et antérieures, en raison de CTAD)
La différence est qu'avec std::pair
, vous devez spécifier les types des deux éléments, tandis que std::make_pair
créera une paire avec le type des éléments qui lui sont passés, sans que vous ayez besoin de lui dire. C'est ce que j'ai pu rassembler de divers documents de toute façon.
Consultez cet exemple sur http://www.cplusplus.com/reference/std/utility/make_pair/
pair one;
pair two;
one = make_pair(10,20);
two = make_pair(10.5,'A'); // ok : conversion implicite à partir de pair
Outre le bonus de conversion implicite, si vous n'utilisiez pas make_pair, vous devriez faire
one = pair(10,20)
à chaque fois que vous affectez à one, ce qui serait agaçant à la longue...
En réalité, les types devraient être déduits au moment de la compilation sans avoir besoin de les spécifier.
@Tor Oui, je sais comment utiliser les deux, je me demandais juste s'il y avait une raison pour std::make_pair
. Apparemment, c'est juste pour la commodité.
Je pense que vous pouvez faire one = {10, 20}
de nos jours mais je n'ai pas de compilateur C++11 sous la main pour le vérifier.
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 inférerait les types de modèle à partir des arguments du constructeur, vous deviez l'écrire explicitement comme :
std::pair p(1, 'a');
C++17 rend cette syntaxe possible, et donc make_pair
est redondant.
Avant C++17, std::make_pair
nous permettait d'écrire un code moins verbeux :
MyLongClassName1 o1;
MyLongClassName2 o2;
auto p = std::make_pair(o1, o2);
au lieu de la version plus verbeuse :
std::pair 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 parce que make_pair
n'est pas un constructeur.
make_pair
est essentiellement équivalent à :
template
std::pair my_make_pair(T1 t1, T2 t2) {
return std::pair(t1, t2);
}
Le même concept s'applique à inserter
vs insert_iterator
.
Voir aussi:
Exemple minimal
Pour rendre les choses plus concrètes, nous pouvons observer le problème de manière minimale avec :
main.cpp
template
struct MyClass {
MyType i;
MyClass(MyType i) : i(i) {}
};
template
MyClass make_my_class(MyType i) {
return MyClass(i);
}
int main() {
MyClass 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: Dans la fonction ‘int main()’:
main.cpp:13:13: erreur: arguments de modèle manquants avant ‘my_class’
MyClass my_class(1);
^~~~~~~~
et nécessite plutôt de fonctionner :
MyClass 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.
Différence pour std::reference_wrapper
Ce commentaire mentionne que std::make_pair
déballe std::reference_wrapper
tandis que le constructeur ne le fait pas, c'est donc une différence. TODO example.
Testé avec GCC 8.1.0, Ubuntu 16.04.
"C++17 rend cette syntaxe possible, et rend donc std::make_pair obsolète." - Pourquoi est-ce que std::make_pair n'est pas devenu obsolète en C++17 ?
@andreee Je ne suis pas sûr, la raison possible est que cela ne cause pas de problème donc pas besoin de casser le vieux code? Mais je ne suis pas familier avec la rationalité du comité C++, ping moi si tu trouves quelque chose.
Une chose utile que j'ai découverte est que pouvoir spécifier les types avec std::make_pair(o1, o2) empêche l'utilisateur de commettre l'erreur de passer des types o1 ou o2 qui ne peuvent pas être implicitement convertis en T1 ou T2. Par exemple, passer un nombre négatif à un unsigned int. -Wsign-conversion -Werror ne détectera pas cette erreur avec le constructeur std::pair en c++11, cependant il détectera l'erreur si std::make_pair est utilisé.
Il n'y a aucune différence entre l'utilisation de make_pair
et l'appel explicite du constructeur pair
avec des arguments de type spécifiés. std::make_pair
est plus pratique lorsque les types sont verbeux car une méthode de modèle a une déduction de type basée sur ses paramètres donnés. Par exemple,
std::vector< std::pair< std::vector, std::vector > > vecOfPair;
std::vector emptyV;
// plus court
vecOfPair.push_back(std::make_pair(emptyV, emptyV));
// plus long
vecOfPair.push_back(std::pair< std::vector, std::vector >(emptyV, emptyV));
Il est intéressant de noter que c'est un idiome commun en programmation de modèles C++. Il est connu sous le nom d'idiome de générateur d'objet, vous pouvez trouver plus d'informations et un bel exemple ici.
Modifier Comme quelqu'un l'a suggéré dans les commentaires (supprimé depuis) ce qui suit est un extrait légèrement modifié du lien au cas où il serait cassé.
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 de classe n'ont pas : Les paramètres de type d'un modèle de fonction sont déduits automatiquement à partir de ses paramètres réels. std::make_pair
est un exemple simple qui renvoie une instance du modèle std::pair
en fonction des paramètres réels de la fonction std::make_pair
.
template
std::pair
make_pair(T t, U u)
{
return std::pair (t,u);
}
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.
7 votes
En C++11, vous pouvez presque entièrement vous passer de make_pair. Voir ma réponse.
4 votes
En C++17,
std::make_pair
est redondant. Il y a une réponse ci-dessous qui détaille cela.1 votes
En résumé : il suffit d'utiliser des accolades. ;)
{ 0, 'a' }
(Toute personne ayant déjà codé en JavaScript appréciera particulièrement cela.)1 votes
std::make_pair(vec.cbegin(), vec.cend())
par rapport àstd::pair::const_iterator, std::vector::const_iterator>(vec.cbegin(), vec.cend())
?