web-dev-qa-db-fra.com

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

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?

162
user542687

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

147
Tor Valamo

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};
31
PlagueHammer

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

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

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;
}
4
EmpZoooli

à 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};
1
Mahmoud Badri