0

假设您有不同的谓词(在这种特殊情况下具有初始状态的函数对象)与 STL 算法(copy_ifsort...)一起使用。事情是谓词可以通过配置更改或用户输入在运行时更改。我考虑过使用多态性和 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;
} 

这个好吗?

我宁愿避免每次我需要过滤字符串时使用 if else 语句,因为过滤器类型可能会在程序的整个生命周期中更改一次或根本不更改。也欢迎对这个问题提出任何其他不同的看法。

4

3 回答 3

0

可能有几种方法可以做到这一点,但这就是多态性的用途。你的代码被简化了,不必记住在每个可以使用的地方添加一个新的case或任何你梦想的新过滤器。else 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从一个中取出 svector并将它们复制到另一个,然后大概另一段代码将迭代那个新的vector并用那些过滤string的 s 做一些事情。考虑一个采用过滤器“用它做某事”功能的设计:

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是运行时值,因此您将在此处进行某种选择。有您if的 's、aswitch或数组查找。我喜欢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

您的示例中的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 回答