简体   繁体   中英

How to erase a player with a given name from a vector

I'm seeing some big bad error messages whilst trying to erase a string from a vector. I'm trying to use the erase-remove idiom but it's not working. Here are some snippets to show my predicament.

team.players.erase( remove(team.players.begin(), team.players.end(),
                            player_name), team.players.end());

team.players is declared in this struct:

struct team 
{
    string name;
    player captain;
    vector<player> players;

};

The vector team.players is populated dynamically as the program runs, and at some point a user has the option to remove a player via a menu.

if (select_option == PRINT_TEAM) print_team(team);
    if (select_option == CHANGE_TEAM_NAME) change_team_name(team);
    if (select_option == CHANGE_CAPTAIN) change_captain(team);
    if (select_option == ADD_PLAYER) add_player(team);
    if (select_option == REMOVE_PLAYER) remove_player(team);
    if (select_option == QUIT) exit(0);

However I'm getting these errors as I tried to compile my program (clang++), long before the function is called. Here are the errors:

/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/algorithm:865:22: error:      invalid operands to binary expression ('player' and 'const      std::__1::basic_string<char>')
        if (*__first == __value_)
            ~~~~~~~~ ^  ~~~~~~~~
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/algorithm:2125:22: note:
      in instantiation of function template specialization
      'std::__1::find<std::__1::__wrap_iter<player *>, std::__1::basic_string<char> >'
      requested here
    __first = _VSTD::find(__first, __last, __value_);
                     ^
program2.cpp:172:25: note: in instantiation of function template specialization
      'std::__1::remove<std::__1::__wrap_iter<player *>, std::__1::basic_string<char>
      >' requested here
    team.players.erase( remove(team.players.begin(), team.players.end(),
                        ^
2 errors generated.

Any idea how I can fix this?

The error message is quite cryptic, especially for beginners, but it seems that the compiler is unable to find out an operator== implementation to compare instances of your player class with std::string objects.

Maybe what you really want is using std::remove_if , specifying a custom condition in which you compare the player's name with the std::string storing the name to remove.

You can express this custom condition using a lambda, eg :

team.players.erase( 
    std::remove_if(
        team.players.begin(), 
        team.players.end(),

        [&player_name](const player& p) {
            return p.name == player_name;
        }),
    team.players.end()
);

You want std::remove_if , not std::remove . You will have to provide a function that takes a player (const reference to avoid copying) and returns bool.

eg (Assumes player has a string member name )

team.players.erase( 
    remove_if(
        team.players.begin(), 
        team.players.end(), 
        [&player_name](const player & p) { return p.name == player_name }), 
    team.players.end());

The problem is that the std::remove() function uses bool operator==() to compare elements of the std::vector<player> with the player_name variable, which is of type std::string .

That's the way how std::remove() recognizes, which elements of the vector it should erase (or, better, move at the end of the container).

However, there is no bool operator==(const player& p, const std::string& name) defined, which is not surprising, as you would have to do it by yourself. Better approach, in this case, IMHO is to use std::remove_if() instead of std::remove() , because std::remove_if() takes a unary function (a function taking one argument and returning bool), which it calls in order to find out if it should remove the element or not.

team.players.erase(remove_if(team.players.begin(), team.players.end(),
    [&player_name](const auto& player) { return player.name == player_name; });

(NOTE: I assumed that player class/struct has a member name of type std::string ).

If you would like to try the operator==() approach, you would have to define something like this:

bool operator==(const player& p, const std::string& name) {
    return p.name == name;
}

bool operator==(const std::string& name, const player& p) {
    return p.name == name;
    // Or, to be more general, you could use
    // return operator==(p, name);
    // here (to call the operator==() version with switched arguments)
}

(Yes, you should return both versions, as - in general - comparison using == should be symmetric).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM