C++中的过滤函数

huangapple go评论79阅读模式
英文:

Filter function in C++

问题

Here is the translated code portion:

我正在尝试通过布尔函数来筛选一些数据。以下是我快速编写的代码,其中存在错误:

```cpp
#include <iostream>
#include <cstring>
#include <vector>

using namespace std;

class Person
{
    private:
    
    string name;
    int age;
    double height;
    char gender;
    
    public:
    
    Person(string name, int age, double height, char gender);
    
    string getName() { return name; }
    int getAge() { return age; }
    double getHeight() { return height; }
    char getGender() { return gender; }
};

Person::Person(string name, int age, double height, char gender)
{
    this->name = name;
    this->age = age;
    this->height = height;
    this->gender = gender;
}

bool IsName(Person p, string name)
{
    if(p.getName() == name) return true;
    return false;
}

int IsAge(Person p, int age)
{
    if(p.getAge() == age) return true;
    return false;
}

double IsHeight(Person p, double height)
{
    if(p.getHeight() == height) return true;
    return false;
}

bool IsGender(Person p, char gender)
{
    if(p.getGender() == gender) return true;
    return false;
}

class Group
{
    public:
    
    vector<Person> People;
    
    template <class T>
    int getPersonCount(bool (*filter)(T), T t);
};

template <class T>
int Group::getPersonCount(bool (*filter)(T), T t)
{
    int ct = 0;
    
    for(int i = 0; i < People.size(); i++) if(filter(People[i], t)) ct++;
    
    return ct;
}

int main()
{
    Person p1("Alice", 24, 1.80, 'F'), p2("Bob", 18, 1.60, 'M'), p3("Charlie", 30, 1.70, 'M');
    
    Group g;
    
    g.People.push_back(p1);
    g.People.push_back(p2);
    g.People.push_back(p3);
    
    cout << g.getPersonCount(&IsName, "Alice");

    return 0;
}

这是您的代码的翻译部分。如果您有其他问题,请随时提出。

英文:

I'm trying to filter some data via boolean functions. Here is my quickly written code, which has errors:

#include &lt;iostream&gt;
#include &lt;cstring&gt;
#include &lt;vector&gt;
using namespace std;
class Person
{
private:
string name;
int age;
double height;
char gender;
public:
Person(string name,int age,double height,char gender);
string getName() {return name};
int getAge() { return age; }
double getHeight() { return height; }
char getGender() { return gender; }
}
Person::Person(string name,int age, double height,char gender)
{
this-&gt;name = name;
this-&gt;age = age;
this-&gt;height = height;
this-&gt;gender = gender;
}
bool IsName(Person p, string name)
{
if(p.getName == name) return true;
return false;
}
int IsAge(Person p, int age)
{
if(p.getAge == age) return true;
return false;
}
double IsHeight(Person p, double height)
{
if(p.getHeight == height) return true;
return false;
}
bool IsGender(Person p, char gender)
{
if(p.getGender == gender) return true;
return false;
}
class Group
{
public:
vector &lt;Person&gt; People;
int getPersonCount(bool (*filter)(int));
}
template &lt;class T&gt;
int Group::getPersonCount(bool (*filter)(T), T t)
{
int ct = 0;
for(int i=0;i&lt;People.size();i++) if(People[i],filter(t)) ct++;
return ct;
}
int main()
{
Person p1(&quot;Alice&quot;,24,1.80,&#39;F&#39;), p2(&quot;Bob&quot;,18,1.60,&#39;M&#39;), p3(&quot;Charlie&quot;,30,1.70,&#39;M&#39;);
Group g;
g.People.push_back(p1);
g.People.push_back(p2);
g.People.push_back(p3);
cout&lt;&lt;g.getPersonCount(&amp;IsName,&quot;Alice&quot;);
return 0;
}

I tried passing the filter function as a parameter using templates. I'd like to know if it's possible to do that in C++. I know it's possible in Lua and I'm just not sure how this could be implemented into C++ code.

答案1

得分: 4

您的IsXXX()函数没有正确调用Person的方法,因为您在方法调用上缺少必需的()括号。此外,IsAge()IsHeight()的返回类型错误,它们都应该是bool

函数应该看起来像这样:

bool IsName(Person p, string name)
{
    return (p.getName() == name);
}

bool IsAge(Person p, int age)
{
    return (p.getAge() == age);
}

bool IsHeight(Person p, double height)
{
    return (p.getHeight() == height);
}

bool IsGender(Person p, char gender)
{
    return (p.getGender() == gender);
}

实际上,您应该将Person对象作为const Person&amp;引用传递,但这要求您还将Person的方法声明为const(因为它们是只读的)。

但是,除此之外,您的代码还有以下问题:

  • Person::getName()方法在return语句上缺少;

  • 每个类声明末尾缺少;

  • Group::getPersonCount()未声明为模板函数,但您试图将其定义为模板函数。

  • getPersonCount()的声明中的参数与其定义中的参数不匹配。

  • 您的IsXXX()函数与getPersonCount()预期的函数签名不匹配。

您可以尝试以下修改:

#include <iostream>
#include <vector>

using namespace std;

class Person
{
private:
    
    string name;
    int age;
    double height;
    char gender;
    
public:
    
    Person(string name, int age, double height, char gender);
    
    string getName() const { return name; };
    int getAge() const { return age; }
    double getHeight() const { return height; }
    char getGender() const { return gender; }
};

Person::Person(string name, int age, double height, char gender)
    : name(name), age(age), height(height), gender(gender)
{
}

bool IsName(const Person& p, const string& name)
{
    return (p.getName() == name);
}

bool IsAge(const Person& p, int age)
{
    return (p.getAge() == age);
}

bool IsHeight(const Person& p, double height)
{
    return (p.getHeight() == height);
}

bool IsGender(const Person& p, char gender)
{
    return (p.getGender() == gender);
}

class Group
{
public:
    
    vector<Person> People;
    
    template <class T, class U>
    int getPersonCount(bool (*filter)(const Person&, T), const U& value)
    {
        int ct = 0;
    
        for(size_t i = 0; i < People.size(); ++i) {
            if (filter(People[i], value))
                ++ct;
        }
    
        return ct;
    }
};

int main()
{
    Person p1("Alice", 24, 1.80, 'F'), p2("Bob", 18, 1.60, 'M'), p3("Charlie", 30, 1.70, 'M');
    
    Group g;
    g.People.push_back(p1);
    g.People.push_back(p2);
    g.People.push_back(p3);
    
    cout << g.getPersonCount(&IsName, "Alice");

    return 0;
}

此外,您可以通过使用模板参数来简化getPersonCount(),而不仅仅是一个输入参数的类型,例如:

class Group
{
public:
    
    // ...

    template <class Filter, class T>
    int getPersonCount(Filter filter, const T& value)
    {
        int ct = 0;
    
        for(size_t i = 0; i < People.size(); ++i) {
            if (filter(People[i], value))
                ++ct;
        }
    
        return ct;
    }
};

这样,您可以使用任何可以使用operator()并接受PersonT作为参数的回调对象,而不仅仅是独立的函数,还可以使用std::bind()的返回值和lambda表达式等。

最后,您可以考虑完全不使用IsXXX()函数,而是使用std::count_if()与lambda作为其谓词,如下所示:

#include <algorithm>

// ...

class Group
{
public:
    
    // ...
    
    template <class Filter>
    int getPersonCount(Filter filter)
    {
        return count_if(People.begin(), People.end(), filter);
    }
};

// ...

cout << g.getPersonCount([](const Person& p){ return p.getName() == "Alice"; });
英文:

Your IsXXX() functions are not calling your Person methods correctly, as you are missing the required () parenthesis on the method calls. Also, the return types on IsAge() and IsHeight() are wrong, they should all be bool.

The functions should look more like this instead:

bool IsName(Person p, string name)
{
return (p.getName() == name);
}
bool IsAge(Person p, int age)
{
return (p.getAge() == age);
}
bool IsHeight(Person p, double height)
{
return (p.getHeight() == height);
}
bool IsGender(Person p, char gender)
{
return (p.getGender() == gender);
}

You really should be passing the Person object as a const Person&amp; reference instead, but that requires you to also quality your Person methods as const (which you should, since they are read-only).

But, that being said, the rest of your code is still not usable, because:

  • your Person::getName() method is missing a ; on the return statement.

  • you are missing ; on the end of each class declaration.

  • Group::getPersonCount() is not declared as a templated function, but you are trying to define it as if it were.

  • the arguments in getPersonCount()'s declaration do not match the arguments in its definition.

  • your IsXXX() functions do not match the function signature that getPersonCount() is expecting anyway.

Try something more like this instead:

#include &lt;iostream&gt;
#include &lt;vector&gt;
using namespace std;
class Person
{
private:
string name;
int age;
double height;
char gender;
public:
Person(string name, int age, double height, char gender);
string getName() const { return name; };
int getAge() const { return age; }
double getHeight() const { return height; }
char getGender() const { return gender; }
};
Person::Person(string name, int age, double height, char gender)
: name(name), age(age), height(height), gender(gender)
{
}
bool IsName(const Person&amp; p, const string&amp; name)
{
return (p.getName() == name);
}
bool IsAge(const Person&amp; p, int age)
{
return (p.getAge() == age);
}
bool IsHeight(const Person&amp; p, double height)
{
return (p.getHeight() == height);
}
bool IsGender(const Person&amp; p, char gender)
{
return (p.getGender() == gender);
}
class Group
{
public:
vector &lt;Person&gt; People;
template &lt;class T, class U&gt;
int getPersonCount(bool (*filter)(const Person&amp;, T), const U&amp; value)
{
int ct = 0;
for(size_t i = 0; i &lt; People.size(); ++i) {
if (filter(People[i], value))
++ct;
}
return ct;
}
};
int main()
{
Person p1(&quot;Alice&quot;, 24, 1.80, &#39;F&#39;), p2(&quot;Bob&quot;, 18, 1.60, &#39;M&#39;), p3(&quot;Charlie&quot;, 30, 1.70, &#39;M&#39;);
Group g;
g.People.push_back(p1);
g.People.push_back(p2);
g.People.push_back(p3);
cout &lt;&lt; g.getPersonCount(&amp;IsName, &quot;Alice&quot;);
return 0;
}

Online Demo

That being said, you can simplify getPersonCount() a little by using a template for the whole type of the filter argument, rather than just the type of one of its input arguments, eg:

class Group
{
public:
...
template &lt;class Filter, class T&gt;
int getPersonCount(Filter filter, const T&amp; value)
{
int ct = 0;
for(size_t i = 0; i &lt; People.size(); ++i) {
if (filter(People[i], value))
++ct;
}
return ct;
}
};

This then allows you to use any callback object that can be invoked with operator() and accepts a Person and a T as arguments. Not just standalone functions, but also the return value of std::bind(), and lambdas too.

Online Demo

In which case, you may as well simply get rid of your IsXXX() functions altogether and use std::count_if() instead with a lambda as its predicate, eg:

...
#include &lt;algorithm&gt;
...
class Group
{
public:
...
template &lt;class Filter&gt;
int getPersonCount(Filter filter)
{
return count_if(People.begin(), People.end(), filter);
}
};
...
cout &lt;&lt; g.getPersonCount( [](const Person &amp;p){ return p.getName() == &quot;Alice&quot;; } );

Online Demo

huangapple
  • 本文由 发表于 2023年6月1日 03:27:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/76376699.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定