1

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?

Community
  • 1
  • 1
Curious
  • 20,870
  • 8
  • 61
  • 146
  • `std::begin()/end()` isn't a great example here - the "rvalue" versions would just yield const iterators, there's no ref-qualification going on. – Barry Oct 29 '16 at 20:51
  • @Barry Doing that was what got me to this question. I just wanted to make the background of this clear so that people understand where I was coming from. – Curious Oct 29 '16 at 20:52
  • If you use a rvalue version, you must accept the fact that the called function may yank your object and leave a valid-but-nulllike state afterwards – krzaq Oct 29 '16 at 20:56
  • @krzaq What about the case when you know your function is non mutating and/or is a member function? – Curious Oct 29 '16 at 21:08
  • @Curious Well, if you know that and still have a use case for using different code for lvalues/rvalues, I'd say go for it. – krzaq Oct 29 '16 at 21:10
  • @krzaq it just feels wrong to me for some reason. Like something in me is screaming "this is not the intended use of `std::forward`" and I just wanted the opinion of some people who knew more about this than I do :) – Curious Oct 29 '16 at 21:16
  • 1
    @Curious Well then, there is a reason why I commented instead of outright answering ;) – krzaq Oct 29 '16 at 21:17

2 Answers2

1

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...
Jarod42
  • 203,559
  • 14
  • 181
  • 302
0

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.

Tomilov Anatoliy
  • 15,657
  • 10
  • 64
  • 169