Quel est le but de std::make_pair
?
Pourquoi ne pas le faire std::pair<int, char>(0, 'a')
?
Y a-t-il une différence entre les deux méthodes?
std::make_pair
est redondant. Il y a une réponse ci-dessous qui détaille cela.
Quel est le but de std::make_pair
?
Pourquoi ne pas le faire std::pair<int, char>(0, 'a')
?
Y a-t-il une différence entre les deux méthodes?
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 vous std::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/
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>
Mis à part le bonus de conversion implicite de celui-ci, si vous n'utilisez pas make_pair, vous devrez le faire
one = pair<int,int>(10,20)
à chaque fois que vous en attribuiez un, ce qui serait ennuyeux avec le temps ...
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):
pair<int, int> p = {1, 2};
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:
std::pair p(1, 'a');
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é:
MyLongClassName1 o1;
MyLongClassName2 o2;
auto p = std::make_pair(o1, o2);
au lieu des 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 ce make_pair
n'est pas un constructeur.
make_pair
équivaut essentiellement à:
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, on peut observer le problème au minimum 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);
}
puis:
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 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_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 .
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 du pair
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,
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 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 du std::pair
modèle en fonction des paramètres réels de la std::make_pair
fonction.
template <class T, class U>
std::pair <T, U>
make_pair(T t, U u)
{
return std::pair <T, U> (t,u);
}
&&
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):
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
juste à l'intérieur insert
et / 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)
emplace
plutôt que insert
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:
std::make_pair(1, 2);
ou
std::pair<int, int>(1, 2);
juste utiliser
{1, 2};
{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};
.