std :: find成员查找对象

Syn*_*ech 3 c++ stl member find

脚本

我在使用STL的时候碰到了一个速度突发,看似正常的情况,在这里简化:

class Person {
  string Name;
  int    Age;
};

vector<Person> people;
AddPeople(people);

string s("Bob");
find(people.begin(), people.end(), s);
Run Code Online (Sandbox Code Playgroud)


问题

不幸的是find想要比较整个班级.


是否有更好或更合适的方式来实现"STL方式"?建议的问题没有帮助,但我设法找到了几个相关的 问题,但没有直接的解决方案.



变通/测试

有一些潜在的解决方法:

  1. find完全放弃(混乱,但可以重构):

    bool bBob = false;
    for (UINT i = 0; i < people.size(); i++) {
      if (people[i].Name == s)
      bBob = true;
      break;
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 提供转换运算符(隐式转换不起作用;显式不能使用find):

    class Person {
      string Name;
      int    Age;
      operator string() {return Name;}
    };
    
    Person b ("Bob", 99);
    string s ("Bob");
           b  == s;     //doesn’t work
    string(b) == s;     //works, but no good for find()
    
    Run Code Online (Sandbox Code Playgroud)
  3. 定义一个独立的相等运算符(简单,有效,但全局公开):

    BOOL operator==(Person l, string r) {
      return l.Name == r;
    }
    
    Run Code Online (Sandbox Code Playgroud)
  4. 定义成员相等运算符(使比较顺序依赖;对象必须是第一个):

    class Person {
      string Name;
      int    Age;
      bool operator==(string s) {return Name == s;}
    };
    
    Person b ("Bob", 99);
    string s ("Bob");
    b==s;               //works
    s==b;               //doesn’t work, but not a problem for find()
    
    Run Code Online (Sandbox Code Playgroud)

看起来#4是最好的候选人,但似乎没有理想或感觉"STL",有些人有问题.

And*_*owl 5

是否有更好或更合适的方式来实现"STL方式"?

你可以使用std::find_if(由C++ 11 lambdas驱动):

std::string name = "Bob";
// ...
std::find_if(std::begin(people), std::end(people), 
    [&] (Person const& p) { return p.Name == name; }
Run Code Online (Sandbox Code Playgroud)

请注意,称其为"STL方式"是不合适的.这是C++标准库,而不是STL("标准模板库").STL是C++标准库的容器和算法库的强大灵感,但两者并不相同.有关详细信息,请参阅StackOverflow上的此问答.

编辑:

由于您使用的是不支持lambda的编译器,因此您可以定义自己的仿函数谓词:

struct person_has_name
{
    person_has_name(std::string const& n) : name(n) { }  
    bool operator () (Person const& p) { return p.Name == name; }
private:
    std::string name;
};
Run Code Online (Sandbox Code Playgroud)

并以std::find_if这种方式使用它:

std::string name = "Bob";
// ...
std::find_if(people.begin(), people.end(), person_has_name(name));
Run Code Online (Sandbox Code Playgroud)


Som*_*ude 1

有几种方法可以做到这一点,所有方法都涉及某种可调用对象和std::find_if.

第一个是使用新的 C++11 lambda:

std::find_if(people.begin(), people.end(), [](const Person& person)
    { return person.Name == "Bob"; });
Run Code Online (Sandbox Code Playgroud)

如果您有一个不支持 lambda 的旧编译器,您可以使用函子对象

class FindPersonByName
{
    std::string name;

public:
    FindPersonByName(const std::string& name) : name(name) {}

    bool operator()(const Person& person) const
        { return person.Name == name; }
};

std::find_if(people.begin(), people.end(), FindPersonByName("Bob"));
Run Code Online (Sandbox Code Playgroud)

当然,这两者都要求您的班级拥有Namepublic 成员。但是您可以将其更改为使用公共GetName函数并将其添加到类中。