2017-09-15 5 views
-1

J'essaye d'écrire une fonction qui renvoie une paire de valeurs d'un conteneur STL.Fonction de modèle STL pour renvoyer une paire

template <typename T> 
std::pair<typename T::value_type,typename T::value_type> getMinMax(T &container) { 

    auto min = *(container.begin()); 
    auto max = *(container.begin()); 

    for (auto it : container) { 
     if (min > (*it)) { 
      min = (*it); 
     } 
     if (max < (*it)) { 
      max = (*it); 
     } 
    } 
    return std::make_pair(min, max); 
}; 

int main() { 
    std::vector<int> c{1, 2, 3, 4, 5}; 
    auto p = getMinMax(c); 
    std::cout << "min: " << p.first << " max: " << p.second << "\n"; 
} 

Je reçois une erreur:

 
error: indirection requires pointer operand ('int' invalid) 
     if (min > (*it)) { 

Je ne sais pas comment faire face à cela. En plus de cette erreur, existe-t-il un meilleur moyen d'implémenter le comportement souhaité?

+2

http://fr.cppreference.com/w/cpp/algorithm/minmax – Justin

+4

* Existe-t-il une meilleure façon de mettre en œuvre le comportement souhaité? *. Oui, ['std :: minmax_element'] (http://fr.cppreference.com/w/cpp/algorithm/minmax_element) – NathanOliver

+3

@ user1211030 Dans cet extrait de code pour (auto it: container) { if (min> (* it)) { min = (* it); } ce n'est pas un itérateur ou un pointeur. Il a le type de valeur. Donc, supprimez le déréférencement. –

Répondre

4

pour la plage renvoie l'élément, pas l'itérateur. Donc, votre boucle doit être quelque chose comme:

for (const auto& e : container) { 
    if (min > e) { 
     min = e; 
    } 
    if (max < e) { 
     max = e; 
    } 
} 
1

Pour commencer la fonction peut avoir un comportement non défini dans le cas où le réservoir est vide, car il peut y avoir une tentative de déréférencement l'itérateur d'un conteneur vide.

Dans les boucles comme ce

for (auto it : container) { 
    if (min > (*it)) { 
     min = (*it); 
    } 

il est mal utilisé déréférencement.

Vous pouvez utiliser l'algorithme standard std::minmax_element. Cependant, il ne fait pas la même chose que votre code. Il renvoie le premier élément minimum et le dernier élément maximum. Donc, vous devriez réécrire l'algorithme std::minmax_element de telle façon que ir renverrait le premier élément minimum (l'itérateur pointant vers le premier élément minimum) et le premier élément maximum (l'itérateur pointant vers le premier élément maximum).

La fonction peut être définie par exemple de la manière suivante

#include <iostream> 
#include <utility> 
#include <vector> 
#include <iterator> 

template <typename T> 
auto getMinMax(T &container) 
    -> std::pair<decltype(container.begin()), decltype(container.begin())> 
{ 
    auto min = container.begin(); 
    auto max = container.begin(); 

    if (!container.empty()) 
    { 
     for (auto it = container.begin(); ++it != container.end(); ) 
     { 
      if (*it < *min) min = it; 
      else if (*max < *it) max = it; 
     } 
    } 

    return { min, max }; 
} 

int main() 
{ 
    std::vector<int> v = { 5, 2, 3, 7, 1, 4, 9, 8, 6 }; 

    auto minmax = getMinMax(v); 

    std::cout << "Minimum = " << *minmax.first 
       << " at position " << std::distance(v.begin(), minmax.first) 
       << " and maximum = " << *minmax.second 
       << " at position " << std::distance(v.begin(), minmax.second) 
       << std::endl; 

    return 0; 
} 

La sortie du programme est

Minimum = 1 at position 4 and maximum = 9 at position 6 
2
template <typename T> 
std::pair<typename T::value_type, typename T::value_type> getMinMax(T &container) { 

    auto min = *(container.begin()); 
    auto max = *(container.begin()); 

    for (const auto& element : container) { /* ERROR WAS HERE, FOR RANGE LOOPS RETURN AN ELEMENT */ 
     if (min > element) { 
      min = element; 
     } 
     if (max < element) { 
      max = element; 
     } 
    } 
    return std::make_pair(min, max); 
}; 

Hey! Cela devrait fonctionner, vous définissez min et max à un element déréférencé, qui bien sûr, n'est pas ce que nous voulons. :)

De même, vous pouvez obtenir un comportement indéfini avec ceci, par exemple, si le container était vide. Peut-être que vous devriez ajouter quelques vérifications qui vérifient cela.

+1

'std :: pair' doit avoir des valeurs, il ne peut pas être vide. Si le conteneur est vide, retourner une valeur par défaut 'std :: pair' contiendrait des valeurs qui pourraient perturber l'appelant comme étant valides quand elles ne le sont pas. Peut-être retourner une 'std :: paire ' à la place, où 'bool' indique succès/échec (similaire à' std :: map :: insert() ')? Sinon, lancez simplement une exception à la place. –

+0

Je ne le savais pas. Merci –

+0

@Remy Lebeau Si le conteneur est vide, la fonction présentée n'a pas de comportement défini. :) –