我有一个学校的任务是创建一个管理猫庇护所的应用程序,我必须提供根据某些标准过滤猫的选项。
我有一个基类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”。
答案 0 :(得分:0)
std::copy_if
接受对可调用对象的引用,而不是指向它的指针。你基本上有两个选择:
在不更改功能签名的情况下,创建引用并将其传递给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;
}
更改您的功能,以便像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"; });
要做到这一点,你可以
使您的过滤器功能成为可接受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;
}
使用类型擦除的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
派生的调用。