【问题标题】:How to use std::find/std::find_if with a vector of custom class objects?如何将 std::find/std::find_if 与自定义类对象向量一起使用?
【发布时间】:2011-10-19 19:52:46
【问题描述】:

我有一个代表名为Nick 的用户的类,我想在其上使用std::find_if,我想在其中查找用户列表向量是否包含与我传入的相同用户名的对象。我做了一些尝试为我要测试的用户名创建一个新的Nick 对象并重载== operator,然后尝试在该对象上使用find/find_if:

    std::vector<Nick> userlist;
    std::string username = "Nicholas";

if (std::find(userlist.begin(), userlist.end(), new Nick(username, false)) != userlist.end())) {
    std::cout << "found";
}

我已经重载了 == operator,所以比较 Nick == Nick2 应该可以工作,但函数返回 error C2678: binary '==' : no operator found which takes a left-hand operand of type 'Nick' (or there is no acceptable conversion)。

这是我的 Nick 课程供参考:

class Nick {
private:
    Nick() {
        username = interest = email = "";
                    is_op = false;
    };
public:
    std::string username;
    std::string interest;
    std::string email;
    bool is_op;

    Nick(std::string d_username, std::string d_interest, std::string d_email, bool d_is_op) {
        Nick();
        username = d_username;
        interest = d_interest;
        email = d_email;
        is_op = d_is_op;
    };
    Nick(std::string d_username, bool d_is_op) {
        Nick();
        username = d_username;
        is_op = d_is_op;
    };
    friend bool operator== (Nick &n1, Nick &n2) {
        return (n1.username == n2.username);
    };
    friend bool operator!= (Nick &n1, Nick &n2) {
        return !(n1 == n2);
    };
};

【问题讨论】:

    标签: stl stl-algorithm c++


    【解决方案1】:

    如果您使用的是 C++0X,则可以使用简单的 lambda 表达式

    std::string username = "Nicholas";    
    std::find_if(userlist.begin(), userlist.end(), [username](Nick const& n){
        return n.username == username;
    })
    

    【讨论】:

    • @Nikko 他也没有说他不是。因此,这个答案开头的“如果”一词。
    • 是的,这一切在 2011 年都有某种意义,也许在我发表评论后进行了编辑......
    • 感谢@mkaes 的出色回答,我已经对以这种方式使用 lambda 函数有了一些了解,但只需要澄清一下,恕我直言,我认为这应该是公认的答案,因为它不需要重载一个运算符,仅在必要时才应该这样做,因为如果过度使用它会导致 API 混乱,所以非常感谢您的回答,帮助很大。 (=
    【解决方案2】:

    您必须将 operator== 定义为类外的两个对象,作为工具函数,而不是成员。

    然后为了让它成为朋友,只需将函数的声明放在类中即可。

    试试这样的:

    class Nick {
    
    public:
        friend bool operator== ( const Nick &n1, const Nick &n2);
    };
    
    
    bool operator== ( const Nick &n1, const Nick &n2) 
    {
            return n1.username == n2.username;
    }
    

    你的发现应该是这样的:

    std::find(userlist.begin(), userlist.end(), Nick(username, false) );
    

    不需要“新”。

    【讨论】:

    • 实际上,与其定义友元函数,不如使用成员函数 bool operator==(const Nick& a)。
    • 您可以选择,但是有很多程序员喜欢在不需要时避免使用成员,并使用 == 之类的运算符作为外部免费朋友函数。我认为标准库实现也是如此。
    • 刚刚按照您的建议进行了尝试。答案不应该是这样的:std::find(userlist.begin(), userlist.end(), &amp;Nick(username, false) );?
    • @Nikko - “外部免费朋友功能”只能在一个班级上工作的优势是什么?
    【解决方案3】:

    我知道您想重载 == 运算符,但同样的事情可以通过谓词轻松完成:

    struct UsernameIs {
        UsernameIs( string s ) : toFind(s) { }
        bool operator() (const Nick &n)
            { return n.username == toFind; }
        string toFind;
    };
    
    int main()
    {
        vector<Nick> vn(10);
        string nameToFind = "something";
        find_if(vn.begin(), vn.end(), UsernameIs(nameToFind));
    }
    

    请注意,在 C++0x 中,您可以更简洁地使用 lambda 表达式做同样的事情。

    【讨论】:

    • 我收到了 error : no match for function UsernameIs 。可能是什么问题?
    【解决方案4】:

    您正在传递一个指向 find 函数的指针。放下新的:

    std::find(userlist.begin(), userlist.end(), Nick(username, false))
    

    此外,您的操作员应该通过 const 引用接受他们的参数,他们不会修改它们。

    bool operator== (const Nick &n1, const Nick &n2)
    

    【讨论】:

      【解决方案5】:

      我注意到您正试图以这种方式从另一个构造函数调用:

      Nick(std::string d_username, bool d_is_op) {
              Nick();
       ...
      

      好吧,对不起,但这不起作用。 Nick() 行只是创建一个临时的,不会影响this。构造函数转发只能在 C++0x(即将推出的标准)中实现

      至于您的问题 - 几天前有关 binary_search 的这个问题涉及相同的理由。最佳答案真是太棒了。

      Mystical restriction on std::binary_search

      HTH。

      附:理想情况下,这应该是一条评论,但它太冗长了

      【讨论】:

        【解决方案6】:

        你可以使用 boost::bind

        std::find_if( userlist.begin(), userlist.end(),
                    boost::bind( & Nick::isFound,
                                 _1 ) );
        

        只需实现 bool Nick::isFound()

        你也可以通过条件

        std::find_if( userlist.begin(), userlist.end(),
                      boost::bind( & Nick::compare,
                                   _1,
                                   nick ) );
        

        实施

        bool Nick::compare( const Nick & nick )
        {
            return this->username == nick.username;
        }
        

        【讨论】:

          【解决方案7】:

          这对我有用:

          尼克.h

          #include <string>
          
          class Nick {
          private:
              Nick() {
                  username = interest = email = "";
                  is_op = false;
              };
          public:
              std::string username;
              std::string interest;
              std::string email;
              bool is_op;
          
              Nick(std::string d_username, std::string d_interest, std::string d_email, bool d_is_op) {
                  Nick();
                  username = d_username;
                  interest = d_interest;
                  email = d_email;
                  is_op = d_is_op;
              };
              Nick(std::string d_username, bool d_is_op) {
                  Nick();
                  username = d_username;
                  is_op = d_is_op;
              };
          
              bool operator==(const Nick& refNick) const
              {
                  if (username != refNick.username)
                      return false;
                  if (interest != refNick.interest)
                      return false;
                  if (email != refNick.email)
                      return false;
                  if (is_op != refNick.is_op)
                      return false;
                  return true;
              }
          
              bool operator!=(const Nick& refNick) const
              {
                  if (username == refNick.username)
                      return true;
                  if (interest == refNick.interest)
                      return true;
                  if (email == refNick.email)
                      return true;
                  if (is_op == refNick.is_op)
                      return true;
                  return false;
              }
          };
          

          main.cpp

          #include <iostream>
          #include <string>
          #include <vector>
          #include "Nick.h"
          
          int main()
          {
              std::vector<Nick> userlist;
              std::string username = "Nicholas";    
              Nick Nicholas(username, false);
              Nick John("John", true);        
              userlist.push_back(Nicholas);
          
              std::vector<Nick>::iterator it;
          
              it = std::find(userlist.begin(), userlist.end(), Nick("Nicholas", false));
              if(it != userlist.end())
                  std::cout << "\n" << Nicholas.username << " was found.";
              else
                  std::cout << "\n" << Nicholas.username << " was not found.";
          
              it = std::find(userlist.begin(), userlist.end(), John);
              if (it != userlist.end())
                  std::cout << "\n" << John.username << " was found.";
              else
                  std::cout << "\n" << John.username << " was not found.";
          }
          

          结果

          Nicholas was found.
          John was not found.
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-04-17
            • 2015-08-06
            • 1970-01-01
            • 1970-01-01
            • 2011-11-12
            相关资源
            最近更新 更多