109 votes

Comment fonctionne std::tie ?

J'ai utilisé std::tie sans trop y réfléchir. Ça marche, alors je l'ai accepté :

auto test()
{
   int a, b;
   std::tie(a, b) = std::make_tuple(2, 3);
   // a is now 2, b is now 3
   return a + b; // 5
}

Mais comment cela magie noire travail ? Comment un temporaire créé par std::tie changement a et b ? Je trouve cela plus intéressant dans la mesure où il s'agit d'une fonctionnalité de la bibliothèque, et non du langage, donc sûrement quelque chose que nous pouvons implémenter nous-mêmes et comprendre.

140voto

bolov Points 4005

Afin de clarifier le concept de base, réduisons-le à un exemple plus élémentaire. Bien que std::tie est utile pour les fonctions qui renvoient (un tuple de) plusieurs valeurs, nous pouvons très bien le comprendre avec une seule valeur :

int a;
std::tie(a) = std::make_tuple(24);
return a; // 24

Des choses que nous devons savoir afin d'aller de l'avant :

  • std::tie construit et renvoie un tuple de références.
  • std::tuple<int> et std::tuple<int&> sont deux classes complètement différentes, sans aucun lien entre elles, si ce n'est qu'elles ont été générées à partir du même modèle, std::tuple .
  • Le tuple a un operator= acceptant un tuple de types différents (mais de même nombre), où chaque membre est assigné individuellement - de Référence cpp :

    template< class... UTypes >
    tuple& operator=( const tuple<UTypes...>& other );

    (3) Pour tout i, assigne std::get<i>(other) à std::get<i>(*this) .

L'étape suivante consiste à se débarrasser de ces fonctions qui ne font que vous gêner, de sorte que nous pouvons transformer notre code en ceci :

int a;
std::tuple<int&>{a} = std::tuple<int>{24};
return a; // 24

L'étape suivante consiste à voir exactement ce qui se passe à l'intérieur de ces structures. Pour cela, je crée 2 types T pour std::tuple<int> et Tr substituant std::tuple<int&> réduit au strict minimum pour nos opérations :

struct T { // substituent for std::tuple<int>
    int x;
};

struct Tr { // substituent for std::tuple<int&>
    int& xr;

    auto operator=(const T& other)
    {
       // std::get<I>(*this) = std::get<I>(other);
       xr = other.x;
    }
};

auto foo()
{
    int a;
    Tr{a} = T{24};

    return a; // 24
}

Et enfin, j'aime me débarrasser des structures toutes ensemble (enfin, ce n'est pas 100% équivalent, mais c'est assez proche pour nous, et assez explicite pour le permettre) :

auto foo()
{
    int a;

    { // block substituent for temporary variables

    // Tr{a}
    int& tr_xr = a;

    // T{24}
    int t_x = 24;

    // = (asignement)
    tr_xr = t_x;
    }

    return a; // 24
}

Donc, en gros, std::tie(a) initialise une référence de membre de données à a . std::tuple<int>(24) crée un membre de données avec la valeur 24 et l'affectation attribue 24 à la référence de l'élément de données dans la première structure. Mais comme ce membre de données est une référence liée à a qui, en fait, attribue 24 à a .

26voto

Damon Points 26437

Cela ne répond pas du tout à votre question, mais permettez-moi de le poster quand même, car C++17 est pratiquement prêt (avec le support du compilateur), donc tout en se demandant comment fonctionnent les choses périmées, il vaut probablement la peine de regarder comment fonctionne la version actuelle, et future, de C++, aussi.

Avec C++17, vous pouvez pratiquement rayer std::tie en faveur de ce que l'on appelle Liaisons structurées . Ils font la même chose (bien, pas la même chose mais ils ont le même effet net), bien que vous deviez taper moins de caractères, il n'a pas besoin du support de la bibliothèque, et vous également ont la possibilité de prendre des références, si c'est ce que vous voulez.

(Notez qu'en C++17 les constructeurs font de la déduction d'argument, donc make_tuple est également devenue quelque peu superflue).

int a, b;
std::tie(a, b) = std::make_tuple(2, 3);

// C++17
auto  [c, d] = std::make_tuple(4, 5);
auto  [e, f] = std::tuple(6, 7);
std::tuple t(8,9); auto& [g, h] = t; // not possible with std::tie

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