108 votes

Pourquoi std :: set n'a pas de fonction membre "contient"?

J'utilise beaucoup std::set<int> et il me suffit souvent de vérifier si un tel ensemble contient un nombre ou non.

Je trouverais naturel d'écrire:

 if (myset.contains(number))
   ...
 

Mais à cause de l’absence d’un membre contains , je dois écrire ce qui est lourd:

 if (myset.find(number) != myset.end())
  ..
 

ou le pas aussi évident:

 if (myset.count(element) > 0) 
  ..
 

Y a-t-il une raison pour cette décision de conception?

153voto

Martin Bonner Points 91

Je pense que c'était probablement parce qu'ils essayaient de rendre std::set et std::multiset aussi semblables que possible. (Et évidemment, count a une signification parfaitement sensée pour std::multiset .)

Personnellement, je pense que c'était une erreur.

Cela n'a pas l'air si mal de prétendre que count est juste une faute de frappe de contains et que vous écrivez le test comme suit:

 if (myset.count(element)) 
   ...
 

C'est quand même dommage.

49voto

Leo Heinsaar Points 177

Pour être en mesure d'écrire if (s.contains()), contains() a-retour d'un bool (ou d'un type convertible bool, ce qui est une autre histoire), comme binary_search .

La raison fondamentale derrière la conception de la décision de ne pas le faire de cette façon c'est qu' contains() qui retourne un bool serait perdre de précieuses informations sur l'endroit où l'élément est dans la collection. find() conserves et renvoie cette information dans la forme d'un itérateur, est donc un meilleur choix pour une bibliothèque générique comme la STL. Cela a toujours été le principe Alex Stepanov, comme il l'a souvent expliqué (par exemple, ici).

Comme à l' count() approche en général, même si c'est souvent une solution de contournement d'accord, le problème c'est qu' il n'a plus de travail que d'un contains() aurait à faire.

Cela ne veut pas dire que l' bool contains() n'est pas très utiles ou même nécessaires. Il y a un moment, nous avons eu une longue discussion à propos de cette même question dans le Standard ISO C++ - les Futures Propositions du groupe.

24voto

Yakk Points 31636

Il n'en a pas parce que personne ne l'a ajouté. Personne n'a ajouté ça parce que les conteneurs de la STL, l' std bibliothèque intégrées conçues pour être minime dans l'interface. (À noter qu' std::string ne vient pas de la STL de la même façon).

Si vous n'avez pas l'esprit de drôles de syntaxe, vous pouvez faux:

template<class K>
struct contains_t {
  K&& k;
  template<class C>
  friend bool operator->*( C&& c, contains_t&& ) {
    auto range = std::forward<C>(c).equal_range(std::forward<K>(k));
    return range.first != range.second;
    // faster than:
    // return std::forward<C>(c).count( std::forward<K>(k) ) != 0;
    // for multi-meows with lots of duplicates
  }
};
template<class K>
containts_t<K> contains( K&& k ) {
  return {std::forward<K>(k)};
}

utilisation:

if (some_set->*contains(some_element)) {
}

Fondamentalement, vous pouvez écrire des méthodes d'extension pour la plupart C++ std types à l'aide de cette technique.

Il fait beaucoup plus de sens de faire ça:

if (some_set.count(some_element)) {
}

mais je suis amusé par la méthode d'extension de la méthode.

Vraiment triste, c'est que l'écriture d'un efficace, contains pourrait être plus rapide sur un multimap ou multiset, comme ils ont juste à en trouver un, alors count a trouver chacun d'eux et de les compter.

Un multiset contenant de 1 milliard de copies de 7 (vous savez, au cas où vous manqueriez) peut avoir une très lente .count(7), mais qui peut avoir une très rapide, contains(7).

Avec l'extension de la méthode, nous avons pu le rendre plus rapide pour ce cas en utilisant lower_bound, en comparaison des end, et en le comparant à l'élément. Faire que pour un non-ordonnée miaou ainsi que d'un ordre miaou aurait besoin de fantaisie SFINAE ou spécifique au conteneur des surcharges.

13voto

Slava Points 4119

Vous êtes à la recherche dans le cas particulier, ne pas voir l'image plus grande. Comme indiqué dans la documentation std::set répond à l'exigence de AssociativeContainer concept. Pour cette notion n'a aucun sens d'avoir contains méthode, comme il est assez inutile pour std::multiset et std::multimap, mais count fonctionne très bien pour tous. Bien que la méthode contains pourrait être ajouté comme un alias pour count pour std::set, std::map et leur haché versions (comme length pour size() en std::string ), mais ressemble à la bibliothèque de créateurs ne voit pas de réel besoin d'elle.

10voto

rustyx Points 2722

Bien que je ne sache pas pourquoi std::set n'a pas contains mais count qui ne retourne que 0 ou 1 , vous pouvez écrire une fonction d’aide contains basée sur un modèle comme celle-ci:

 template<class Container, class T>
auto contains(const Container& v, const T& x)
-> decltype(v.find(x) != v.end())
{
    return v.find(x) != v.end();
}
 

Et utilisez-le comme ceci:

     if (contains(myset, element)) ...
 

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