web-dev-qa-db-ja.com

std :: setに「含む」メンバー関数がないのはなぜですか?

私はstd::set<int>を頻繁に使用しており、そのようなセットに数字が含まれているかどうかを確認するだけです。

私は書くのが自然だと思うでしょう:

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

しかし、containsメンバーがないため、面倒なことを書く必要があります。

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

またはそれほど明白ではない:

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

この設計決定の理由はありますか?

95
Jabberwocky

おそらく、彼らがstd::setstd::multisetを可能な限り似せようとしているからだと思います。 (そして明らかにcountstd::multisetに対して完全に理にかなった意味を持ちます。)

個人的にはこれは間違いだと思います。

countcontainsのつづりが間違っていると見せかけ、テストを次のように記述しても、それほど悪くは見えません。

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

それでも残念です。

144
Martin Bonner

if (s.contains())を記述できるようにするには、contains()binary_searchのようにbool(またはboolに変換可能な型)を返す必要があります。

基本的理由設計決定の背後にあるnotこの方法でそれを行うには、boolを返すcontains()要素の場所に関する貴重な情報を失うコレクションにありますfind()は、その情報を反復子の形式で保存して返すため、STLのような汎用ライブラリーの場合に適しています。彼がよく説明したように、これは常にアレックスステパノフの指針でした(たとえば here )。

一般的なcount()アプローチについては、大丈夫な回避策であることが多いですが、問題はacontains()する必要があります

それは、bool contains()が非常にいいものではなく、必要でさえないということではありません。しばらく前に、ISO C++標準-将来の提案グループでこのまったく同じ問題について 長い議論 がありました。

38
Leo Heinsaar

特定のケースを調査しており、大きな画像は表示されていません。 ドキュメントstd::setで述べられているように、 AssociativeContainer コンセプトの要件を満たしています。このコンセプトでは、containsメソッドを使用しても意味がありません。std::multisetおよびstd::multimapにはほとんど役に立たないためですが、countメソッドはすべて正常に機能します。メソッドcontainsは、std::setstd::map、およびそれらのハッシュバージョン(std::stringsize()のようなcountなど)のlengthのエイリアスとして追加できますが、ライブラリ作成者が追加したように見えますそれの本当の必要性を見ない。

12
Slava

std::setcontainsがなく、0または1のみを返すcountがない理由はわかりませんが、テンプレート化されたcontainsヘルパー関数を次のように記述できます。

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();
}

そして、次のように使用します:

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

setの本当の理由は私には謎ですが、mapのこの同じデザインの考えられる説明の1つは、人々が誤って非効率的なコードを書くことを防ぐためです。

if (myMap.contains("Meaning of universe"))
{
    myMap["Meaning of universe"] = 42;
}

これは、2つのmapルックアップになります。

代わりに、イテレーターを取得する必要があります。これにより、イテレータを再利用する必要があるという精神的なヒントが得られます。

auto position = myMap.find("Meaning of universe");
if (position != myMap.cend())
{
    position->second = 42;
}

mapルックアップを1つだけ消費します。

setmapが同じ肉から作られていることに気付いたら、setにもこの原則を適用できます。つまり、setに存在する場合にのみsetのアイテムを操作する場合、この設計により、次のようにコードを記述できなくなります。

struct Dog
{
    std::string name;
    void bark();
}

operator <(Dog left, Dog right)
{
    return left.name < right.name;
}

std::set<Dog> dogs;
...
if (dogs.contain("Husky"))
{
    dogs.find("Husky")->bark();
}

もちろん、これはすべて単なる推測にすぎません。

7
Martin Drozdik

Binary_searchはどうですか?

 set <int> set1;
 set1.insert(10);
 set1.insert(40);
 set1.insert(30);
 if(std::binary_search(set1.begin(),set1.end(),30))
     bool found=true;
0
Massimiliano D