6

からのテンプレート関数を使用すると、<algorithm>次のようなことができます

struct foo
{
    int bar, baz;
};

struct bar_less
{
    // compare foo with foo
    bool operator()(const foo& lh, const foo& rh) const
    {
        return lh.bar < rh.bar;
    }
    template<typename T>  // compare some T with foo
    bool operator()(T lh, const foo& rh) const
    {
        return lh < rh.bar;
    }
    template<typename T>  // compare foo with some T
    bool operator()(const foo& lh, T rh) const
    {
        return lh.bar < rh;
    }
};

int main()
{
    foo foos[] = { {1, 2}, {2, 3}, {4, 5} };
    bar_less cmp;
    int bar_value = 2;
    // find element {2, 3} using an int
    auto it = std::lower_bound(begin(foos), end(foos), bar_value, cmp);
    std::cout << it->baz;
}

このstd::setようなメソッドでは、ダミーオブジェクトの作成を余儀なくされるfindタイプのオブジェクトを渡す必要があります。set::key_type

set<foo> foos;
foo search_dummy = {2,3};  // don't need a full foo object;
auto it = foos.find(search_dummy);

と呼べばとても助かりますfoos.find(2)find少ない述語に渡すことができるすべてのものを受け入れて、テンプレートになれない理由はありますか?そして、それがちょうど欠けているのなら、なぜそれはC ++ 11ではないのですか(私はそうではないと思います)。

編集

主な質問は、なぜそれが不可能であり、それが可能であるならば、なぜそれを提供しないという基準を決定したのかということです。回避策を提案できる2番目の質問:-)(boost::multi_index_container値型からのキー抽出を提供する、今私の頭に浮かぶ)

値型を構築するのにより費用がかかる別の例。キーnameはタイプの一部であり、マップキーのコピーとして使用しないでください。

struct Person
{
    std::string name;
    std::string adress;
    std::string phone, email, fax, stackoferflowNickname;
    int age;
    std::vector<Person*> friends;
    std::vector<Relation> relations;
};

struct PersonOrder
{
    // assume that the full name is an unique identifier
    bool operator()(const Person& lh, const Person& rh) const
    {
        return lh.name < rh.name;
    }
};

class PersonRepository
{
public:

    const Person& FindPerson(const std::string& name) const
    {
        Person searchDummy;  // ouch
        searchDummy.name = name;
        return FindPerson(searchDummy);
    }

    const Person& FindPerson(const Person& person) const;

private:
    std::set<Person, PersonOrder> persons_;
    // what i want to avoid
    // std::map<std::string, Person> persons_;
    // Person searchDummyForReuseButNotThreadSafe;

};
4

5 に答える 5

3

std::find_ifソートされていない範囲で動作します。したがって、必要な述語を渡すことができます。

std::set<T>コレクションの順序を維持し、要素を再度検索するために、常にComparatorテンプレート引数 (デフォルト) を使用します。std::less<T>

したがって、std::set::findテンプレート化されている場合は、コンパレータの全体的な順序を観察する述語のみを渡す必要があります。

繰り返しにstd::lower_boundなりますが、ソートされた範囲で機能する他のすべてのアルゴリズムは、すでにそれを正確に必要としているため、それは新しい要件でも驚くべき要件でもありません。

find_if()だから、 (言う)がないのは単なる見落としだと思いstd::setます。C++17 用に提案してください :) (編集: : EASTLには既にこれがあり、彼らは私よりもはるかに優れた名前を使用していました:) find_as

とはいえ、を使用してはいけないことはstd::setわかっていますね。ソートされたベクトルは、ほとんどの場合より高速であり、 に欠けている柔軟性を提供しますstd::set

編集: Nicol が指摘したように、BoostLokifind()にはこの概念の実装があります (他の場所と同様に) が、それらの主な利点 (組み込みメソッド) を使用できないため、ネイキッドを使っても大した損にはなりませんstd::vector

于 2012-06-17T00:13:58.830 に答える
2

std::set::find対数時間の複雑さを持つ標準状態。実際には、これはソート基準として使用される厳密な弱順序std::set比較を使用して、二分探索ツリーとして実装することによって達成されます。同じ厳密な弱い順序付け基準を満たさないルックアップは、対数的複雑度を満たしません。したがって、これは設計上の決定です。対数の複雑さが必要な場合は、 を使用します。複雑さと柔軟性を交換できる場合は、セットでstd::find_ifを使用します。std::set::find

于 2012-06-17T06:13:05.807 に答える
1

彼らはあなたが望むものを提供しましたが、あなたが考えているものとはかなり異なる方法で提供しました.

実際には、2 つの異なる方法があります。1 つは、1) 暗黙的に使用できる、2) 比較に本当に必要な要素のサブセットのみを必要とする、含まれているクラスのコンストラクターを構築することです。これを配置すると、検索を実行できfoods.find(2);ます。から一時オブジェクトを作成し、2その一時オブジェクトを見つけることになりますが、それは真の一時オブジェクトになります。コードで明示的に (どこでも) 処理する必要はありません。

編集:ここで話しているのは、マップに保存しているのと同じタイプのインスタンスを作成することですが、(おそらく)初期化されていない「キー」として使用していないフィールドを残します(または初期化されます) 「存在しない」と言っているものに)。例えば:

struct X { 
   int a; // will be treated as the key
   std:::string data;
   std::vector<int> more_data;
public:
   X(int a) : a(a) {} // the "key-only" ctor
   X(int a, std::string const &d, std::vector<int> const &m); // the normal ctor
};

std::set<X> s;

if (s.find(2)) { // will use X::X(int) to construct an `X`
    // we've found what we were looking for
}

はい、X単一引数のコンストラクターを使用して (または私が X と呼んでいるもの) を構築する場合、構築したものは検索以外には使用できない可能性があります。

編集終了]

ライブラリがより直接的なサポートを提供する 2 番目の方法は、多くの場合、少し単純です。実際に要素のサブセット (おそらく 1 つだけ) を検索に使用している場合は、 のstd::map代わりに を作成できますstd::set。ではstd::map、キー タイプとして指定したもののインスタンスの検索が、明示的/直接的にサポートされています。

于 2012-06-16T21:03:12.073 に答える
0

実行したい場合は、2 つの 間の比較に加えて、 と比較std::find(2)する方法を定義する必要があるためです。しかし、とは異なる型であるため、実際には 2 つの追加関数が必要になります。intfoofoointfoo

bool operator<(int, foo);
bool operator<(foo, int);

(または他の論理的に同等のペア)。

これを行うと、実際にはとの間の全単射関数を定義していることになり、単純に a と be を使用することもできます。intfoostd::map<int, foo>

それでもソートは必要ないstd::mapが、ソートされた検索の利点が必要な場合は、実際にはダミー オブジェクトを使用するのが最も簡単な方法です。

確かに、標準std::setはメンバー関数を提供できます。これには、 a を受け取りfoo、検索されたものよりも小さい、等しい、または大きい場合は -1、0、1 を返す関数を渡します... しかし、それは C++ の方法ではありません。bsearch()そして、同じ型の引数を 2 つ取ることさえあることに注意してください!

于 2012-06-17T00:33:31.010 に答える
0

key_type は、最初のテンプレート パラメーターであり、コンテナーに格納される要素の型である Key のエイリアスとしてセット コンテナーで定義されるメンバー型です。

ドキュメントを参照してください。

ユーザー定義型の場合、ライブラリがキーの型を知る方法はありません。特定のユース ケースでは、キー タイプがint. を使用する場合は、set< int > s;を呼び出すことができますs.find( 2 );set< foo >ただし、 a を検索して整数のみを渡したい場合は、コンパイラを支援する必要があります( と の間でsetの順序付けがどのように機能するかを考えてください)。fooint

于 2012-06-16T20:48:39.193 に答える