En C ++ 11, vous pouvez presque entièrement vous passer de make_pair. Voyez ma réponse .
PlagueHammer
2
En C ++ 17, std::make_pairest redondant. Il y a une réponse ci-dessous qui détaille cela.
Drew Dormann
Réponses:
165
La différence est qu'avec std::pairvous devez spécifier les types des deux éléments, alors que vous std::make_paircréerez une paire avec le type des éléments qui lui sont passés, sans que vous ayez besoin de le dire. C'est ce que je pourrais tirer de divers documents de toute façon.
En fait, les types doivent être déduits au moment de la compilation sans qu'il soit nécessaire de les spécifier.
Chad
@Tor Ouais, je sais comment utiliser les deux, j'étais juste curieux de savoir s'il y avait une raison à cela std::make_pair. Apparemment, c'est juste pour des raisons de commodité.
@Jay Il semblerait que oui.
Tor Valamo
15
Je pense que vous pouvez le faire de one = {10, 20}nos jours, mais je n'ai pas de compilateur C ++ 11 à portée de main pour le vérifier.
MSalters
6
Notez également que cela make_pairfonctionne avec les types sans nom, y compris les structures, les unions, les lambdas et autres doodads.
Mooing Duck le
35
Comme @MSalters a répondu ci-dessus, vous pouvez maintenant utiliser des accolades pour le faire en C ++ 11 (je viens de vérifier cela avec un compilateur C ++ 11):
main.cpp:Infunction‘int main()’:
main.cpp:13:13: error: missing template arguments before ‘my_class’MyClass my_class(1);^~~~~~~~
et nécessite au contraire 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.
Différence pour `std :: reference_wrapper
Ce commentaire mentionne que std::make_pairdéballestd::reference_wrapper alors que le constructeur ne le fait pas, c'est donc une différence. Exemple TODO.
"C ++ 17 rend cette syntaxe possible, et donc make_pair redondant." - Pourquoi n'est-ce std::make_pairpas devenu obsolète dans C ++ 17?
andreee
@andreee Je ne suis pas sûr, la raison possible est que cela ne crée aucun problème, donc pas besoin de casser l'ancien code? Mais je ne suis pas familier avec le raisonnement du comité C ++, envoyez-moi un ping si vous trouvez quelque chose.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
1
Une chose utile que j'ai rencontrée est que la possibilité de spécifier les types avec std :: make_pair <T1, T2> (o1, o2) empêche l'utilisateur de faire l'erreur de passer des types o1 ou o2 qui ne peuvent pas être implicitement cast en T1 ou T2. Par exemple, passer un nombre négatif à un int non signé. -Wsign-conversion -Werror n'attrapera pas cette erreur avec le constructeur std :: pair en c ++ 11 mais il interceptera l'erreur si std :: make_pair est utilisé.
conchoecia
make_pairdéballe les wrappers de référence, donc c'est différent de CTAD en fait.
LF
26
Il n'y a aucune différence entre l'utilisation make_pairet l'appel explicite du pairconstructeur avec des arguments de type spécifiés. std::make_pairest plus pratique lorsque les types sont détaillés car une méthode de modèle a une déduction de type basée sur ses paramètres donnés. Par exemple,
Il convient de noter qu'il s'agit d'un idiome courant dans la programmation de modèles C ++. Il est connu sous le nom d'idiome Object Generator, vous pouvez trouver plus d'informations et un bel exemple ici .
Modifier Comme quelqu'un l'a suggéré dans les commentaires (supprimés depuis), ce qui suit est un extrait légèrement modifié du lien en cas de rupture.
Un générateur d'objets permet la création d'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 de ses paramètres réels. std::make_pairest un exemple simple qui renvoie une instance du std::pairmodèle en fonction des paramètres réels de la std::make_pairfonction.
make_pair crée une copie supplémentaire sur le constructeur direct. Je saisis toujours mes paires pour fournir une syntaxe simple.
Cela montre la différence (exemple de Rampal Chaudhary):
Je suis presque sûr que la copie supplémentaire sera élidée dans tous les cas, si les paramètres d'optimisation du compilateur sont suffisamment élevés.
Björn Pollex
1
Pourquoi voudriez-vous jamais compter sur les optimisations du compilateur pour l'exactitude?
sjbx
J'obtiens les mêmes résultats avec les deux versions, et avec std::movejuste à l'intérieur insertet / ou autour de quoi ferait référence sample. Ce n'est que lorsque je passe std::map<int,Sample>à std::map<int,Sample const&>cela que je réduis le nombre d'objets construits, et seulement lorsque je supprime le constructeur de copie que j'élimine toutes les copies (évidemment). Après avoir apporté ces deux modifications, mon résultat comprend un appel au constructeur par défaut et deux appels au destructeur pour le même objet. Je pense que je dois manquer quelque chose. (g ++ 5.4.1, c ++ 11)
John P
FWIW Je suis d'accord pour dire que l'optimisation et l'exactitude devraient être complètement indépendantes, car c'est exactement le type de code que vous écrivez pour vérifier la cohérence après que différents niveaux d'optimisation produisent des résultats incohérents. En général, je recommanderais emplaceplutôt que insertsi vous construisiez simplement une valeur à insérer immédiatement (et vous ne voulez pas d'instances supplémentaires.) Ce n'est pas mon domaine d'expertise, si je peux même dire que j'en ai un, mais le copier / déplacer la sémantique introduite par C ++ 11 m'a beaucoup aidé.
John P
Je crois que je rencontre exactement le même problème et après avoir débogué pendant environ toute la soirée, je suis finalement arrivé ici.
lllllllllllll
1
à partir de c ++ 11, utilisez simplement une initialisation uniforme pour les paires. Donc au lieu de:
{1, 2}peut être utilisé pour initialiser une paire, mais ne s'engage pas pour la paire de types. À- dire lors de l' utilisation automatique , vous devez vous engager à un type sur l'ERS: auto p = std::pair{"Tokyo"s, 9.00};.
std::make_pair
est redondant. Il y a une réponse ci-dessous qui détaille cela.Réponses:
La différence est qu'avec
std::pair
vous devez spécifier les types des deux éléments, alors que vousstd::make_pair
créerez une paire avec le type des éléments qui lui sont passés, sans que vous ayez besoin de le dire. C'est ce que je pourrais tirer de divers documents de toute façon.Voir cet exemple sur http://www.cplusplus.com/reference/std/utility/make_pair/
Mis à part le bonus de conversion implicite de celui-ci, si vous n'utilisez pas make_pair, vous devrez le faire
à chaque fois que vous en attribuiez un, ce qui serait ennuyeux avec le temps ...
la source
std::make_pair
. Apparemment, c'est juste pour des raisons de commodité.one = {10, 20}
nos jours, mais je n'ai pas de compilateur C ++ 11 à portée de main pour le vérifier.make_pair
fonctionne avec les types sans nom, y compris les structures, les unions, les lambdas et autres doodads.Comme @MSalters a répondu ci-dessus, vous pouvez maintenant utiliser des accolades pour le faire en C ++ 11 (je viens de vérifier cela avec un compilateur C ++ 11):
la source
Les arguments du modèle de classe n'ont pas pu être déduits du constructeur avant C ++ 17
Avant C ++ 17, vous ne pouviez pas écrire quelque chose comme:
car cela inférerait les types de modèles à partir des arguments du constructeur.
C ++ 17 rend cette syntaxe possible, et donc
make_pair
redondante.Avant C ++ 17,
std::make_pair
nous permettait d'écrire du code moins détaillé:au lieu des plus verbeux:
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 ce
make_pair
n'est pas un constructeur.make_pair
équivaut essentiellement à:Le même concept s'applique à
inserter
vsinsert_iterator
.Voir également:
Exemple minimal
Pour rendre les choses plus concrètes, on peut observer le problème au minimum avec:
main.cpp
puis:
compile joyeusement, mais:
échoue avec:
et nécessite au contraire de travailler:
ou l'assistant:
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éballestd::reference_wrapper
alors que le constructeur ne le fait pas, c'est donc une différence. Exemple TODO.Testé avec GCC 8.1.0, Ubuntu 16.04 .
la source
std::make_pair
pas devenu obsolète dans C ++ 17?make_pair
déballe les wrappers de référence, donc c'est différent de CTAD en fait.Il n'y a aucune différence entre l'utilisation
make_pair
et l'appel explicite dupair
constructeur avec des 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 a une déduction de type basée sur ses paramètres donnés. Par exemple,la source
Il convient de noter qu'il s'agit d'un idiome courant dans la programmation de modèles C ++. Il est connu sous le nom d'idiome Object Generator, vous pouvez trouver plus d'informations et un bel exemple ici .
Modifier Comme quelqu'un l'a suggéré dans les commentaires (supprimés depuis), ce qui suit est un extrait légèrement modifié du lien en cas de rupture.
Un générateur d'objets permet la création d'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 de ses paramètres réels.
std::make_pair
est un exemple simple qui renvoie une instance dustd::pair
modèle en fonction des paramètres réels de lastd::make_pair
fonction.la source
&&
depuis C ++ 11.make_pair crée une copie supplémentaire sur le constructeur direct. Je saisis toujours mes paires pour fournir une syntaxe simple.
Cela montre la différence (exemple de Rampal Chaudhary):
la source
std::move
juste à l'intérieurinsert
et / ou autour de quoi ferait référencesample
. Ce n'est que lorsque je passestd::map<int,Sample>
àstd::map<int,Sample const&>
cela que je réduis le nombre d'objets construits, et seulement lorsque je supprime le constructeur de copie que j'élimine toutes les copies (évidemment). Après avoir apporté ces deux modifications, mon résultat comprend un appel au constructeur par défaut et deux appels au destructeur pour le même objet. Je pense que je dois manquer quelque chose. (g ++ 5.4.1, c ++ 11)emplace
plutôt queinsert
si vous construisiez simplement une valeur à insérer immédiatement (et vous ne voulez pas d'instances supplémentaires.) Ce n'est pas mon domaine d'expertise, si je peux même dire que j'en ai un, mais le copier / déplacer la sémantique introduite par C ++ 11 m'a beaucoup aidé.à partir de c ++ 11, utilisez simplement une initialisation uniforme pour les paires. Donc au lieu de:
ou
juste utiliser
la source
{1, 2}
peut être utilisé pour initialiser une paire, mais ne s'engage pas pour la paire de types. À- dire lors de l' utilisation automatique , vous devez vous engager à un type sur l'ERS:auto p = std::pair{"Tokyo"s, 9.00};
.