C ++:term不会计算为带有1个参数的函数

时间:2018-04-05 15:24:12

标签: c++ class abstract-class

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

我有一个基类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;
}

我希望能够通过不同类型的过滤从Controller调用过滤器功能。 例如:

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

过滤应该包含品种Birman的猫。

或者对于以下代码:

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

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

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

但是当我编译代码时,它给了我错误:“术语不会评估为带有1个参数的函数”。错误来自函数“copy_if”。

1 个答案:

答案 0 :(得分:0)

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;
    }
    
  3. 与现在删除的评论相反,传递值不是一种选择。多态性仅适用于指针和引用,而不适用于副本。

    此外,使用函数对象的基类是不流行的。现代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;
      }
      
    3. 这两个仍然会接受Filter派生的调用。