C++:术语的计算结果不是采用 1 个参数的函数



我有一个学校的任务,创建一个管理猫收容所的应用程序,我必须提供根据某些标准过滤猫的选项。

我有一个基类 Filter,以及两个派生类,用于按年龄和品种过滤猫。

class Filter
{
public:
virtual bool operator()(const Cat & cat) const = 0;
virtual ~Filter() {}
};

class FilterOfBreed : public Filter
{
private:
std::string breed;
public:
FilterOfBreed(const std::string & b) : breed(b) {}
bool operator()(const Cat & cat) const override { return this->breed.length() == 0 || this->breed == cat.getBreed(); }
};

class FilterAgeLessThan : public Filter
{
private:
int age;
public:
FilterAgeLessThan(int a) : age(a) {}
bool operator()(const Cat & cat) const override { return cat.getAge() <= this->age; }
};

在我的控制器中,我有过滤器功能,它使用copy_if进行过滤。

vector<Cat> Controller::filter(const Filter * filter)
{
vector<Cat> result;
copy_if(this->repo.getCats().begin(), this->repo.getCats().end(), back_inserter(result), filter);
return result;
}

我希望能够使用不同类型的过滤从控制器调用过滤器函数。 例如:

Filter * filter = new FilterOfBreed("Birman");
vector<Cat> filtered = ctrl.filter(filter);

过滤后应包含伯曼品种的猫。

或者对于以下代码:

Filter * filter = new FilterAgeLessThan(3);
vector<Cat> filtered = ctrl.filter(filter);

过滤应包含年龄小于或等于 3 的猫。

为了进行过滤,我需要一个函数来接收两个参数并检查它们之间是否存在某种关系。但是函数"copy_if"必须接收一元谓词作为最后一个参数。我在这里的一篇文章中读到,我可以使用指向 copy_if 中类的指针(该类具有附加参数作为成员),并重载该类的 operator()。这就是我创建类过滤器的原因。

但是当我编译代码时,它给了我一个错误:"术语没有计算为一个接受 1 个参数的函数"。错误来自函数"copy_if"。

>std::copy_if接受对可调用对象的引用,而不是指向它的指针。 您基本上有两种选择:

  1. 在不更改函数签名的情况下,进行引用并将其传递给copy_if

    vector<Cat> Controller::filter(const Filter * filter)
    {
    vector<Cat> result;
    copy_if(repo.getCats().begin(), repo.getCats().end(),
    back_inserter(result), *filter);
    //   THIS ASTERISK IS THE KEY ^^^
    return result;
    }
    
  2. 更改函数以获取引用,就像copy_if一样:

    vector<Cat> Controller::filter(const Filter & filter)
    //           CHANGED TO AMPERSAND HERE ^^^
    {
    vector<Cat> result;
    copy_if(repo.getCats().begin(), repo.getCats().end(),
    back_inserter(result), filter);
    return result;
    }
    

与现已删除的评论相反,按值传递不是一种选择。 多态性仅适用于指针和引用,不适用于副本。

此外,对函数对象使用基类也不流行。 现代C++样式通常会为此使用 lambda:

vector<Cat> filtered =
ctrl.filter([](const Cat& cat){ return cat.getBreed() == "Birman"; });

要做到这一点,你可以

  1. 使您的筛选函数成为可以接受 lambda 类型的模板:

    template<typename Predicate>
    vector<Cat> Controller::filter(const Predicate & filter)
    {
    vector<Cat> result;
    copy_if(repo.getCats().begin(), repo.getCats().end(),
    back_inserter(result), filter);
    return result;
    }
    
  2. 使用执行类型擦除的std::function,这与多态性几乎相同,但不需要继承:

    vector<Cat> Controller::filter(std::function<bool(const Cat&)> filter)
    {
    vector<Cat> result;
    copy_if(repo.getCats().begin(), repo.getCats().end(),
    back_inserter(result), filter);
    return result;
    }
    

这两者仍将接受Filter派生的调用。

最新更新