Imaginons que vous deviez appeler la méthode suivante:
std::Tuple<int, int, int> foo();
En C++ 17, vous pouvez appeler la fonction et décompresser le tuple sur une seule ligne:
auto [a, b, c] = foo();
Maintenant, comment puis-je continuer à stocker uniquement b
et c
et à ignorer a
?
Actuellement, je ne connais que deux options:
1 - Je peux utiliser une variable factice lors de la décompression automatique
Cependant, la variable muette sera inutilisée et émettra un avertissement. Par conséquent, si je veux taire cet avertissement, le code sera assez désagréable à voir:
#pragma warning(Push)
#pragma warning(disable:4101)
// ReSharper disable once CppDeclaratorNeverUsed
auto [_, b, c] = foo();
#pragma warning(pop)
2 - Je peux stocker le tuple entier et utiliser std::get
pour récupérer la référence aux seules variables dont j'ai besoin. Le code est moins désagréable mais la syntaxe est également moins simple.
De plus, la taille de ce code augmente d'une ligne pour chaque nouvelle valeur que nous souhaitons conserver dans le tuple.
auto Tuple = foo();
int b = std::get<1>(Tuple);
int c = std::get<2>(Tuple);
Existe-t-il une autre méthode plus simple pour décompresser uniquement quelques paramètres dans un tuple?
Une autre alternative consiste à utiliser un std::tie
:
int b, c;
std::tie(std::ignore, b, c) = foo();
Éditer
Comme mentionné dans les commentaires, cette approche pose certains problèmes:
Malheureusement, liaisons structurées == ne prend pas explicitement en charge le rejet de membres et d'attributs tels que [[maybe_unused]]
ne peut pas être appliqué à liaisons structurées (il existe une proposition pour cela: P0609 : "Attributs pour les liaisons structurées" ).
Voici une solution possible:
auto [a, b, c] = foo();
(void) a; // unused
Vous pouvez écrire une fonction d'assistance qui ne vous restitue que certains indices d'un std::Tuple
:
template <size_t... Is, typename Tuple>
auto take_only(Tuple&& Tuple) {
using T = std::remove_reference_t<Tuple>;
return std::Tuple<std::Tuple_element_t<Is, T>...>(
std::get<Is>(std::forward<Tuple>(Tuple))...);
}
auto [b, c] = take_only<1, 2>(foo());
Ou laisse tomber la tête ou quelque chose:
template <size_t... Is, typename Tuple>
auto drop_head_impl(Tuple&& Tuple, std::index_sequence<0, Is...> ) {
return take_only<Is...>(std::forward<Tuple>(Tuple));
}
template <typename Tuple>
auto drop_head(Tuple&& Tuple) {
return drop_head_impl(std::forward<Tuple>(Tuple),
std::make_index_sequence<std::Tuple_size_v<std::decay_t<Tuple>>>());
}
auto [b, c] = drop_head(foo());
Mais les implémentations ci-dessus ont presque certainement des problèmes de complexité de la durée de vie que l'utilisation directe de liaisons structurées ne résoudra pas - car il n'y a pas d'extension de durée de vie ici.
Alors, faites quoi dit Vittorio :
auto [a, b, c] = foo();
(void)a;
MSVC a déjà corrigé ceci dans l'aperçu VS 15.7. La version finale 15.7 devrait être disponible dans les prochaines semaines. Cela signifie que la logique actuelle prise en charge par les dernières versions de tous les principaux compilateurs est la suivante:
Si aucune des liaisons dans une déclaration de liaison structurée n'est utilisée, il est possible de faire taire l'avertissement à l'aide de la commande [[maybe_unused]]
attribut:
[[peut-être_utilisé]] auto [a, b, c] = foo ();