225 votes

Quel est le but de std::make_pair par rapport au constructeur de std::pair?

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?

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.)

206voto

Tor Valamo Points 14209

(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...

2 votes

En réalité, les types devraient être déduits au moment de la compilation sans avoir besoin de les spécifier.

0 votes

@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é.

24 votes

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.

48voto

Nocturne Points 9973

Comme @MSalters l'a répondu ci-dessus, vous pouvez maintenant utiliser des accolades pour le faire en C++11 (j'ai vérifié cela avec un compilateur C++11):

pair p = {1, 2};

47voto

Ciro Santilli Points 3341

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.

2 votes

"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 ?

1 votes

@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.

2 votes

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é.

26voto

devil Points 1049

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));

0 votes

Encore plus court: vecOfPair.emplace_back(emptyV, emptyV);

21voto

mkm Points 335

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);
}

2 votes

@duck En fait && depuis C++11.

Prograide.com

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.

Powered by:

X