Can you pass an additional parameter to a predicate?

时光毁灭记忆、已成空白 提交于 2019-12-20 10:33:10

问题


I'm trying to filter a vector so it contains only a specific value.

e.g. Make sure the vector only contains elements of the value "abc."

Right now, I'm trying to achieve this with remove_copy_if.

Is there any way to pass an additional parameter to a predicate when using one of std's algorithms?

std::vector<std::string> first, second;
first.push_back("abc");
first.push_back("abc");
first.push_back("def");
first.push_back("abd");
first.push_back("cde");
first.push_back("def");

std::remove_copy_if(first.begin(), first.end(), second.begin(), is_invalid);

I'm hoping to pass the following function as a predicate but it seems more likely that this would just end up comparing the current value being examined by remove_copy_if and the next.

bool is_invalid(const std::string &str, const std::string &wanted)
{
   return str.compare(wanted) != 0;
}

I have a feeling I'm probably approaching this wrong so any suggestions would be appreciated!

Thanks


回答1:


Define a functor instead:

struct is_invalid
{
    is_invalid(const std::string& a_wanted) : wanted(a_wanted) {}
    std::string wanted;
    bool operator()(const std::string& str)
    {
        return str.compare(wanted) != 0;
    }
};

std::remove_copy_if(first.begin(),
                    first.end(),
                    second.begin(),
                    is_invalid("abc"));

or if C++11 use a lambda:

std::string wanted("abc");
std::remove_copy_if(first.begin(), first.end(), second.begin(), 
    [&wanted](const std::string& str)
    {
        return str.compare(wanted) != 0;
    });

Note that the output vector, second, must have elements before the call to remove_copy_if():

// Create 'second' after population of 'first'.
//
std::vector<std::string> second(first.size());

std::string wanted = "abc";
int copied_items    = 0;
std::remove_copy_if( first.begin(), first.end(), second.begin(),
    [&wanted, &copied_items](const std::string& str) -> bool
    {
        if (str.compare(wanted) != 0) return true;
        copied_items++;
        return false;
    });
second.resize(copied_items);

As functor predicates are copied more effort is required to retain the copied_items information. See Pass std algos predicates by reference in C++ for suggested solutions.




回答2:


Make functor, or use std/boost::bind.

struct is_invalid
{
public:
   is_invalid(const std::string& w):wanted(w) { }
   bool operator () (const std::string& str)
   {
       return str.compare(wanted) != 0;
   }
private:
   std::string wanted;
};

std::remove_copy_if(first.begin(), first.end(), second.begin(), is_invalid("abc"));

Example with bind

bool is_invalid(const std::string &str, const std::string &wanted)
{
   return str.compare(wanted) != 0;
}

std::remove_copy_if(first.begin(), first.end(), second.begin(),
boost::bind(is_invalid, _1, "abc"));


来源:https://stackoverflow.com/questions/13525361/can-you-pass-an-additional-parameter-to-a-predicate

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!