33 votes

Existe-t-il un moyen de gérer facilement les fonctions renvoyant std :: pairs?

C ++11 a la fonction std::minmax_element qui renvoie une paire de valeurs. Ceci, cependant, est assez déroutant à manipuler et à lire, et produit une variable supplémentaire, plus tard inutile, pour polluer la portée.

 auto lhsMinmax = std::minmax_element(lhs.begin(), lhs.end());
int &lhsMin = *(lhsMinMax.first);
int &lhsMax = *(lhsMinmax.second);
 

Y a-t-il une meilleure manière de faire cela? Quelque chose comme:

 int lhsMin;
int lhsMax;
std::make_pair<int&, int&>(lhsMin, lhsMax).swap(
    std::minmax_element(lhs.begin(), lhs.end()));
 

32voto

Jarod42 Points 15729

Avec la liaison structurée de C ++1z, vous pouvez directement faire

 auto [lhsMinIt, lhsMaxIt] = std::minmax_element(lhs.begin(), lhs.end());
 

23voto

KrzaQ Points 1

Pour éviter de polluer votre champ d'application, vous pouvez inclure la tâche dans un champ plus petit:

 int lhsMin, lhsMax;

{
    auto it = std::minmax_element(lhs.begin(), lhs.end());
    lhsMin = *it.first;
    lhsMax = *it.second;
}
 

sinon, vous pouvez utiliser un lambda

 int lhsMin, lhsMax;

std::tie(lhsMin, lhsMax) = [&]{
    auto it = std::minmax_element(lhs.begin(), lhs.end());
    return std::make_tuple(*it.first, *it.second);
}();
 

13voto

Quentin Points 3904

Cela ressemble assez à un cas commun à l'invite d'une fonction d'assistance:

template <class T, std::size_t...Idx>
auto deref_impl(T &&tuple, std::index_sequence<Idx...>) {
    return std::tuple<decltype(*std::get<Idx>(std::forward<T>(tuple)))...>(*std::get<Idx>(std::forward<T>(tuple))...);
}

template <class T>
auto deref(T &&tuple)
    -> decltype(deref_impl(std::forward<T>(tuple), std::make_index_sequence<std::tuple_size<std::remove_reference_t<T>>::value>{})) {
    return deref_impl(std::forward<T>(tuple), std::make_index_sequence<std::tuple_size<std::remove_reference_t<T>>::value>{});
}

// ...

int lhsMin;
int lhsMax;
std::tie(lhsMin,lhsMax) = deref(std::minmax_element(lhs.begin(), lhs.end()));

index_sequence est le C++14, mais la pleine mise en œuvre peut être fait en C++11.

Note: je garderais le répétées decltype en deref's type de retour, même en C++14, de sorte que SFINAE peuvent s'appliquer.

Voir en direct sur Coliru

4voto

Barry Points 45207

Je venais d'être plus direct et d'écrire ma propre version de l' minmax_element:

template <class Iter, class R = typename iterator_traits<Iter>::reference>
std::pair<R,R> deref_minmax(Iter first, Iter last)
{
    auto iters = std::minmax_element(first, last);
    return std::pair<R,R>{*iters.first, *iters.second};
}

Qui est alors simplement:

int lo, hi;
std::tie(lo, hi) = deref_minmax(lhs.begin(), lhs.end());

Cela permettrait de vous limiter à une seule copie des éléments (ce qui n'est pas un big deal avec des ints), vous permettent également de maintenir l'accès à la référence dans le conteneur réel.


En C++17, pour le plaisir, nous pourrions écrire une généralisé dereferencer:

template <class Tuple>
auto deref(Tuple&& tup) {
    return std::apply([](auto... args) {
        return std::tuple <decltype(*args)...>(*args...);
    }, tup);
}

auto& [lo, hi] = deref(std::minmax_element(lhs.begin(), lhs.end()));

Ici, lo et hi sont des références dans le conteneur lui-même.

2voto

Vašek Potoček Points 758

Il n'y a aucun moyen de l'attribution de deux références à la fois dans la révision actuelle de la norme, si c'est ce que vous êtes après. Notez qu'aucune des autres réponses ne sont que, à l'exception de Barry, qui nécessite C++17 et un aide de modèle.

Toutefois, si vous souhaitez un accès en lecture-écriture à votre minimale et maximale des éléments, pourquoi ne pas simplement aller avec les itérateurs l' minmax_element vous fournit directement? Il est susceptible de générer identiques code machine comme moyen de références, de toute façon, au moins si votre lhs est ContiguousContainer mais peut-être que dans d'autres cas aussi.

Vous devrez compter un peu moins sur le type automatique déduction, par exemple,

decltype(lhs.begin()) lhsMinIt, lhsMaxIt;
std::tie(lhsMinIt, lhsMaxIt) = std::minmax_element(lhs.begin(), lhs.end());
/* now access your minimum and maximum as *lhsMinIt and *lhsMaxIt */

Si vous connaissez le type d' lhs sera l'un des conteneurs standard, vous pouvez utiliser un peu plus propre désignation de type, decltype(lhs)::iterator.

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