In my project I have function like this:
bool VectorList::put(const Pair &p);
This adds the Pair
into the VectorList
by copying the Pair
.
I can use it like this:
Pair p { "key", "value" };
VectorList v;
v.put(p);
// or
v.put(Pair{ "anotherkey", "anothervalue" });
However in second case an unnecessary object is created, so I want to do
bool VectorList::put(Pair &&p);
I checked how this is done in vector (gcc, llvm) and there is 100% same code in both methods, except equal / std::move() line.
Is there some way I could do it without code duplication?
put()
looks similar to this:
struct Node{
Pair pair;
AdditionalThings at;
};
bool VectorList::put(const Pair &p){
if (not_good_for_insert(p))
return false;
// ...
Node node = create_node();
node.pair = p;
// ...
return true;
}
Yes, use perfect forwarding:
template <typename P>
bool VectorList::put (P &&p) {
//can't forward p here as it could move p and we need it later
if (not_good_for_insert(p))
return false;
// ...
Node node = create_node();
node.pair = std::forward<P>(p);
// ...
return true;
}
Another possibility is to just pass by value like in Maxim's answer. The advantage of the perfect-forwarding version is that it requires no intermediate conversions if you pass in compatible arguments and performs better if moves are expensive. The disadvantage is that forwarding reference functions are very greedy, so other overloads might not act how you want.
Note that Pair &&p
is not a universal reference, it's just an rvalue reference. Universal (or forwarding) references require an rvalue in a deduced context, like template arguments.