Как использовать std :: find / std :: find_if с вектором пользовательских объектов класса? - PullRequest
26 голосов
/ 04 августа 2011

У меня есть класс, представляющий пользователя с именем 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).

Вот мой класс Ника для справки:

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);
    };
};

Ответы [ 6 ]

38 голосов
/ 04 августа 2011

Если вы используете C ++ 0X, вы можете использовать простое лямбда-выражение

std::string username = "Nicholas";    
std::find_if(userlist.begin(), userlist.end(), [username](Nick const& n){
    return n.username == username;
})
16 голосов
/ 04 августа 2011

Вы должны определить оператор == с двумя объектами вне вашего класса, как функцию инструмента, а не члена.

Затем, чтобы сделать его другом, просто поместите объявление функции внутри класса.

попробуйте что-то вроде этого:

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) );

Нет необходимости "нового".

9 голосов
/ 04 августа 2011

Я знаю, что вы хотели перегрузить оператор ==, но то же самое можно легко сделать с помощью предиката:

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 вы можете сделать то же самоевещь с лямбда-выражением гораздо лаконичнее.

3 голосов
/ 04 августа 2011

Вы передаете указатель на функцию поиска.Отбросьте новое:

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

Кроме того, ваши операторы должны принимать свои аргументы по константной ссылке, они не изменяют их.

bool operator== (const Nick &n1, const Nick &n2)
1 голос
/ 04 августа 2011

Я заметил, что вы пытаетесь вызвать один конструктор из другого следующим образом:

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

Хорошо, извините, но это не работает. Строка Nick() просто создает временную и не влияет на this. Переадресация конструктора возможна только в C ++ 0x (будущий стандарт)

Что касается вашей проблемы - этот вопрос, заданный пару дней назад, о binary_search охватывает те же основания. Лучший ответ просто потрясающий.

Мистическое ограничение на std :: binary_search

НТН.

P.S. В идеале это должен был быть комментарий, но он слишком многословный

0 голосов
/ 04 августа 2011

Вы можете использовать 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;
}
...