Reputation: 21560
I was in a position where I was using std::forward
wherever I had a forwarding reference and I was wondering if some of that was unnecessary or even wrong. For example having std::forward
in a std::begin()
call.
Because of the ability of a class being able to overload its member functions based on whether the call is made with the object as an rvalue or not https://akrzemi1.wordpress.com/2014/06/02/ref-qualifiers/, I assumed that a templated function would be as efficient as possible if you were knew that the inner function you were forwarding the object to was non-mutating and/or was a member function of the object. For example
template <typename Something>
void do_something(Something&& something) {
std::forward<Something>(something).do_something();
auto iter = std::begin(std::forward<Something>(something));
for_each(iter, std::end(std::forward<Something>(something), []() {});
}
I saw this question (When not to use std::forward with r-values?) but it did not address the member function ref-qualifiers and it also did not clearly address what the best practice is when you don't have access to the inner functions definitions that you are calling.
Is there a general guideline for when not to use std::forward
that addresses the things I mentioned? Or is there some key concept that I am missing?
Upvotes: 1
Views: 305
Reputation: 16741
The problem is a use after object moved from ("stealed"). If something
used in a multiple lines of do_something
, then use std::forward
only at the last such line to prevent the problem.
Upvotes: 0
Reputation: 218278
Except if you know the type you will have, avoid to use std::forward
several time in the same function for the same object, as the second time, your object might be moved.
// assuming implementation which really need pass by value instead of const reference
template <typename T> void pass_by_value(T t) { std::cout << t; }
template <typename T>
void foo(T&& t)
{
pass_by_value(std::forward<T>(t));
pass_by_value(std::forward<T>(t));
}
a call of foo
with std::string
foo(std::string("Hello world")); // or "Hello world"s
might call the equivalent to
pass_by_value(std::string("Hello world"));
pass_by_value(std::string("")); // Moved string...
Upvotes: 1