简体   繁体   中英

C++ best way to build vector of strings from multiple returns of function calls

I'm practicing C++, so this is not code that will go into production, but I'm very curious to know:

I have a vector of pointers to objects of type Player :

std::vector<Player*> _players;

Each player returns me his name as std::string when I call it's method get_name() , for example:

std::string player0_name = _players[0]->get_name();

I want to pass all player names to a function that expects them as reference to a vector of strings:

void all_player_names( std::vector< std::string >& );

Now I know it would be easy to do this via some temporary variable. I could first create a vector of strings, store all player names there, then pass it to the function all_player_names as reference.

But I'm looking for a way of doing that without having to create a temporary variable. It should be something similar like a list comprehension in Python. It has to iterate over the array of Player pointers, call the get_name() function on each of them, build a vector out of the returned strings and directly pass it to the function all_player_names . I'm assuming it should be possible with lambda functions and some algorithm from the STL, but I don't know which one.

So it should look more or less like that:

all_player_names(<function that i'm looking for>(
    _players, [](Player* p) { return p->get_name();}
);

Is there such an algorithm in the STL?

Easiest way would be using accumulate and using a temporary variable that will be passed through the binary op and returned:

std::accumulate(_players.begin(), _players.end(), 
 std::vector<std::string>(),
 [](std::vector<std::string>& vector, const Player* elem) 
   {
    vector.push_back(elem->get_name());
    return vector;
   });

Thanks to move semantics it should have almost no performance overhead in C++11.

In my opinion it is better to use standard algorithm std::transform instead of std::accumulate. The semantic of std::transform is more clear in this case compared with the semantic of std::accumulate. For example

    struct Player
    {
    public:
        Player( const std::string &s ) : s( s ) {}
        const std::string & get_name() const
        {
            return s;
        }
    private:
        std::string s;
    };

    std::vector<Player *> v1;

    v1.push_back( new Player( "Hello" ) );
    v1.push_back( new Player( "Player" ) );

    std::vector<std::string> v2;
    v2.reserve( v1.size() );


    std::transform( v1.begin(), v1.end(), std::back_inserter( v2 ), 
                    std::mem_fun( &Player::get_name ) );

    for ( const std::string &s : v2 ) std::cout << s << ' ';
    std::cout << std::endl;

If you have an argument that is const ref you have no option but to construct a variable. Your const ref should point to some existing object. You can change your function to take a pointer to function and a const ref to std::vector<Player*> . Make the function take a pointer to Player and return his name.

What you want is to use lambda-expression (or anonymous function).

With C++11 is now possible, but not with previous version. Problem is treated also here .

In your case i would use a method in a new class Players:

class Players {
public:
    void addPlayer(Player*);
    void removePlayer(Player*);
    vector<string> getNames() {
      std::vector<string> names;
      for(unsigned int i = 0; i != players_.size(); ++i) {
        names.push_back(players_[i]->getName());
      }
    return names;
    }
private:
vector<Player*> players_;

};

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