0

STL アルゴリズム ( など) で使用するさまざまな述語 (この特定のケースでは初期状態の関数オブジェクト) があるとしcopy_ifますsort。問題は、構成の変更またはユーザー入力によって実行時に述語が変更される可能性があることです。私は polymorphism と virtual を使用することを考えましたが、このような解決策operator()に落ち着きましたstd::function(これは私を C++11 の領域に置きますが、それは問題ありません)

struct PlainFilter {
    PlainFilter(string filter):m_filter(filter)
    {}
    bool operator() (const string& toMatch)
    {one way}
};
struct AcronymFilter {
    AcronymFilter (string filter):m_filter(filter)
    {}
    bool operator() (const string& toMatch)
    {a different way}
};

enum FilterTypes {plain,acronym};

vector<string> FilterStuff(string filter, vector<string> in)
{
     vector<string> out;
     std::function<bool(const string&)> foo;

     if( filterType == plain)
         foo = PlainFilter(filter);
     else if( filterType == acronym)
         foo = AcronymFilter(filter);

     copy_if(in.begin(),in.end(),back_inserter(out),foo);
     return out;
} 

これでいいですか?

プログラムの存続期間中にフィルターの種類が 1 回またはまったく変更されない可能性があるため、文字列をフィルター処理する必要があるたびに if else ステートメントを使用することは避けたいと思います。問題に対する他の異なる見方も大歓迎です..

4

3 に答える 3

0

はランタイム値であるためfilterType、ここで何らかの選択が行われます。ifswitch、または配列ルックアップがあります。私がswitch一番気に入っているのは、配列のルックアップにはより複雑な型が必要であり、オプティマイザーがそれを処理すると、それ以上速くなることはありません。const &また、反射だけで値ではなくイニシャライザを渡します。

そうは言っても、あなたの方法は問題ないと思います。それを行う別の方法:

bool plain_string_test(const string& filter, const string& candidate) 
{  /* ... one way ... */ }

bool acronym_string_test(const string& filter, const string& candidate)
{  /* ... or another ... */ }

enum FilterTypes {plain,acronym};

vector<string> FilterStuff(string filter, vector<string> in)
{
     vector<string> out;
     std::function<bool(const string&, const string&)> filtermethod;

     switch(filterType) {
     default: throw some_domain_error(some_constructor_here);

     case plain:      filtermethod = plain_string_test;         break;
     case acronym:    filtermethod = acronym_string_test;       break;

     }

     copy_if(in.begin(),in.end(),back_inserter(out), 
         [&filtermethod, &filter](const string& candidate) -> bool
             { return filtermethod(filter,candidate); }
     return out;
}

私はこれの方が好きです。型のスキャフォールディングとコピーをいくつか排除し、文字列テストをより再利用しやすくします (または関数のスキャフォールディングも排除します)。ここでは、関数の静的配列からより良い値を取得できる可能性がありますが、それはおそらくコンテキストに依存します。

キーボードから編集ボックスへの警告、私はこのコードをテストしていませんが、少なくとも通信には十分正しいと思います.

于 2013-01-26T04:53:39.537 に答える
0

これを行うにはおそらくいくつかの方法がありますが、これがポリモーフィズムの目的です。コードは単純化されており、使用できるすべての場所で新しいフィルターを追加したり、思いついた新しいフィルターを追加したりすることを覚えておく必要はありませんcaseelse if

struct IFilter
{
    virtual bool operator()(const std::string &) const = 0;
};

struct PlainFilter : public IFilter
{
    virtual bool operator()(const std::string &filter) const override
    {
        // do something
    }
};

struct AcronymFilter : public IFilter
{
    virtual bool operator()(const std::string &filter) const override
    {
        // do something else
    }
};


std::vector<std::string> FilterStuff(const IFilter &filter, const std::vector<std::string> &in)
{
    std::vector<std::string> out;
    std::copy_if(in.begin(), in.end(), std::back_inserter(out), filter);

    return out;
}

ただし、個人的にはFilterStuff別の方法で実装します。stringあるものから s を取得して別の svectorにコピーすると、おそらく別のコードがその新しいものを反復処理しvector、それらのフィルター処理された s で何かを実行しますstring。代わりに、フィルター「それで何かを行う」機能を使用する設計を検討してください。

void EnumerateStuff(const IFilter &filter, const std::vector<std::string> &in,
                    std::function<void(std::string)> callback)
{
    for (const auto &s : in)
    {
        if (filter(s))
        {
            callback(s);
        }
    }
}

FilterStuffEnumerateStuffフィルタリングされたコピーが本当に必要な場合は、次のように記述できます。

std::vector<std::string> FilterStuff(const IFilter &filter, const std::vector<std::string> &in)
{
    std::vector<std::string> out;

    EnumerateStuff(filter, in,
        [&](const std::string &s)
        {
            out.push_back(s);
        });

    return out;
}
于 2013-01-26T03:39:48.387 に答える
0

filterTypeあなたの例の変数は何ですか? アプリケーション/アルゴリズムの構成可能なパラメーターがあると思いますか??

とにかく、私は次のことを提案します:

1) 構成可能なすべてのパラメーターを構造体に収集します。

class configuration
{
public:
    /// Type of predicate functor
    typedef std::function<bool(const std::string&)> predicate_type;

    struct plain_filter { /* your implementation */ };
    struct acronym_filter { /* your implementation */ };

    /// Type of predicate to use
    enum class predicate_type { plain, acronym };

    /// Set predicate
    void set_filter_kind(const predicate_type ft)
    {
        switch (ft)
        {
        case predicate_type::plain:
            m_predicate = plain_filter();
            break;
        case predicate_type::acronym:
            m_predicate = acronym_filter();
            break;
        default:
            assert(!"Invalid filter type");
        }
    }

    /// Get filter to be used by algorithms
    /// \todo Consider to return a const reference instead of copy,
    /// but make sure your filters are state-less (as expected by STL slgorithms)
    decltype(m_predicate) use_filter() const
    {
        return m_predicate;
    }

    // other configuration parameters/methods

private:
    predicate_type m_predicate;
};

configuration2)コマンドライン オプション、設定ファイル、またはユーザー入力からのインスタンスを埋めます。このインスタンスをコードの必要なすべての部分から見えるようにします (たとえば、applicationクラスのメンバーにして、(読み取り専用) アクセスするメソッドを提供するか、このようにします...)

3) アルゴリズムで構成データを使用する

std::vector<string> filter_stuff(string filter, const std::vector<string>& in)
{
    std::vector<string> out;
    std::copy_if(
        begin(in)
      , end(in)
      , std::back_inserter(out)
      , application().get_config().use_filter()
      );
    return out;
}

PS:ところで、in参照(または右辺値参照)を介してパラメーターを渡します...コピーが必要かどうかは本当に疑問です(値で渡します)

于 2013-01-26T03:55:20.357 に答える