This question is migrated from Code Review since it is marked off-topic over there
I need to pass an rvalue-reference (temporary) as a parameter to a function taking unversal reference. It be used multiple times inside. Each function calling it accepts rvalue-reference as special overload. My question is how we should forward the parameter.
Following is an example:
#include <iostream>
#include <vector>
using namespace std;
struct Game {
Game(const std::string& n) : name(n) {}
Game(std::string&& n) : name(std::move(n)) {}
std::string name;
};
struct Student {
// constructor: not important for the discussion
Student(const string& n) : name(n){}
Student(string&& n) : name(std::move(n)) {}
// play has overloaded for several different types
void play(const std::string& game) {
cout << name << " plays |" << game << "| (L)"<< endl;
games.emplace_back(game);
}
void play(std::string&& game) {
cout << name << " plays |" << game << "| (R)"<< endl;
games.emplace_back(std::move(game));
}
void play(const Game& game) {
cout << name << " plays |" << game.name << "| (L)"<< endl;
games.emplace_back(game);
}
void play(Game&& game) {
cout << name << " plays |" << game.name << "| (R)"<< endl;
games.emplace_back(std::move(game));
}
std::string name;
std::vector<Game> games;
};
struct Class {
// construct: not important here. Did not overload for &&
Class(const vector<string>& names) {
for (auto name : names) {
students.emplace_back(std::move(name));
}
}
// perfect forwarding works nice
template <typename G>
void play_by_first(G&& game) {
if (students.size() == 0) return;
students[0].play(std::forward<G>(game));
}
// this is relevant part.
// How to code for a generic game of type G and
// game might or might not be temporary
template <typename G>
void play(G&& game) {
for (auto& student : students) {
student.play(std::forward<G>(game)); // <--- how to change this line
}
}
vector<Student> students;
};
int main() {
// normal here
Class grade1({"alice"});
grade1.play("football");
grade1.play(Game("basketball"));
cout << endl;
// Charlie has nothing to play
Class grade2({"bob", "Charlie"});
grade2.play(std::string{"football"});
grade2.play(Game("basketball"));
}
As you can see, when we only need to use it once, as in play_by_first
, perfect forwarding (std::forward
) will be the ultimate solution. However, when it used multiple times, the rvalues will be invalid after the first call.
Is there a standard way in modern c++ to handle this? I still wanna to have some optimization for temporaries. So at least the last call should resolve to the rvalue reference overload.
I also looked into the std library, tried to learn from implementations such as find_if
where the predicator can be an rvalue reference and will be called multiple times. Howerver, it does not take universal reference, and cannot handle rvalue references specially.
Aucun commentaire:
Enregistrer un commentaire