La norme C++ 17 introduit une nouvelle fonctionnalité des liaisons structurées , qui avait été initialement proposée en 2015 et dont l'apparence syntaxique a été largement discutée plus tard.
Certaines utilisations viennent à l’esprit dès que vous parcourez la documentation.
Décomposition des agrégats
Déclarons un tuple:
std::Tuple<int, std::string> t(42, "foo");
Des copies élémentaires nommées peuvent être facilement obtenues avec des liaisons structurées sur une seule ligne:
auto [i, s] = t;
qui équivaut à:
auto i = std::get<0>(t);
auto s = std::get<1>(t);
ou
int i;
std::string s;
std::tie(i, s) = t;
Les références aux éléments Tuple peuvent également être obtenues sans douleur:
auto& [ir, sr] = t;
const auto& [icr, scr] = t;
Nous pouvons donc utiliser des tableaux ou des structures/classes dont tous les membres sont publics.
Valeurs de retour multiples
Un moyen pratique d'obtenir plusieurs valeurs de retour d'une fonction découle immédiatement de ce qui précède.
Quoi d'autre?
Pouvez-vous fournir d'autres cas d'utilisation, peut-être moins évidents, pour les liaisons structurées? Sinon, comment peuvent-ils améliorer la lisibilité ou même les performances du code C++?
Remarques
Comme mentionné dans les commentaires, certaines fonctionnalités ne sont pas implémentées dans les liaisons structurées. Ils ne sont pas variadiques et leur syntaxe ne permet pas d'ignorer explicitement les membres de l'agrégat. Ici on peut trouver une discussion sur la variadicité.
Pouvez-vous fournir d'autres cas d'utilisation, peut-être moins évidents, pour les liaisons structurées? Sinon, comment peuvent-ils améliorer la lisibilité ou même les performances du code C++?
Plus généralement, vous pouvez l'utiliser pour (laissez-moi dire) décompresser une structure et remplir un ensemble de variables:
struct S { int x = 0; int y = 1; };
int main() {
S s{};
auto [ x, y ] = s;
(void)x, void(y);
}
L'inverse aurait été:
struct S { int x = 0; int y = 1; };
int main() {
S s{};
auto x = s.x;
auto y = s.y;
(void)x, void(y);
}
La même chose est possible avec les tableaux:
int main() {
const int a[2] = { 0, 1 };
auto [ x, y ] = a;
(void)x, void(y);
}
Quoi qu'il en soit, cela fonctionne également lorsque vous renvoyez la structure ou le tableau d'une fonction, vous pouvez probablement affirmer que ces exemples appartiennent au même ensemble de cas que vous avez déjà mentionné.
Un autre bon exemple mentionné dans les commentaires à la réponse de @TobiasRibizel est la possibilité de parcourir les conteneurs et de décompresser facilement le contenu.
Comme exemple basé sur std::map
:
#include <map>
#include <iostream>
int main() {
std::map<int, int> m = {{ 0, 1 }, { 2, 3 }};
for(auto &[key, value]: m) {
std::cout << key << ": " << value << std::endl;
}
}
Pouvez-vous fournir d'autres cas d'utilisation, peut-être moins évidents, pour les liaisons structurées?
Ils peuvent être utilisés pour implémenter get<N>
pour les structures - voir magic_get
'S G&EACUTE;N&EACUTE;R&EACUTE; AUTOMATIQUEMENT core17_generated.hpp
. Ceci est utile car il fournit une forme primitive de réflexion statique (par exemple, une itération sur tous les membres d’un struct
).
Sauf preuve contraire, je pense que les liaisons structurées ne sont qu'un moyen de traiter les API héritées. IMHO, les API qui requièrent SB auraient dû être corrigées à la place.
Donc, au lieu de
auto p = map.equal_range(k);
for (auto it = p.first; it != p.second; ++it)
doSomethingWith(it->first, it->second);
nous devrions pouvoir écrire
for (auto &e : map.equal_range(k))
doSomethingWith(e.key, e.value);
Au lieu de
auto r = map.insert({k, v});
if (!r.second)
*r.first = v;
nous devrions pouvoir écrire
auto r = map.insert({k, v});
if (!r)
r = v;
etc.
Bien sûr, quelqu'un trouvera un usage intelligent à un moment donné, mais pour moi, après un an de connaissances à leur sujet, ils restent un mystère non résolu. Esp. étant donné que le document est co-écrit par Bjarne, qui n'est généralement pas connu pour introduire des fonctionnalités ayant une applicabilité aussi étroite.