【问题标题】:Can you pass an additional parameter to a predicate?您可以将附加参数传递给谓词吗?
【发布时间】:2012-11-23 08:28:40
【问题描述】:

我正在尝试过滤矢量,使其仅包含特定值。

例如确保向量仅包含值为“abc”的元素。

现在,我正在尝试通过remove_copy_if 实现这一目标。

在使用 std 的一种算法时,有什么方法可以将附加参数传递给谓词?

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

我希望将以下函数作为谓词传递,但这似乎更有可能最终只是比较 remove_copy_if 和下一个正在检查的当前值。

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

我有一种感觉,我可能正在接近这个错误,所以任何建议都将不胜感激!

谢谢

【问题讨论】:

  • 只是想知道 - 你用只有相同元素的向量做什么?
  • 我试图让我的示例尽可能简单,这样才有意义 :) 我所做的就是从符合特定模式(使用正则表达式)的向量中删除元素。

标签: c++ predicate


【解决方案1】:

改为定义一个仿函数:

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"));

或者如果 C++11 使用 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;
    });

注意输出向量second必须在调用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);

随着仿函数谓词的复制,需要付出更多努力来保留copied_items 信息。有关建议的解决方案,请参阅 Pass std algos predicates by reference in C++

【讨论】:

  • 当我尝试使用此解决方案时,我似乎收到关于“未定义引用”的错误,关于可能发生的任何想法?
  • @noko,您可以将代码发布到 ideone 或类似网站吗?请注意,您的编译器必须支持 C++11 lambda(在 g++ 中您需要使用 -std=c++0x 编译器开关)。
  • 没关系,我忘了在函数前添加一个 ClassName:: :(
【解决方案2】:

制作函子,或使用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"));

绑定示例

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"));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-06-26
    • 1970-01-01
    • 1970-01-01
    • 2011-12-20
    • 1970-01-01
    • 2017-03-19
    • 2017-09-17
    相关资源
    最近更新 更多