I'm learning std::forward
. I wrote a short program to test what would happen if we do not call std::forward
before forwarding the arguments to another function call:
#include <iostream>
#include <typeinfo>
#include <string>
using namespace std;
class Example {
};
ostream &operator << (ostream &os, const Example &e) { os << "yes!"; return os; }
void test_forward_inner(const Example &e) { cout << "& " << e << endl; }
void test_forward_inner(Example &&e) { cout << "&& " << e << endl; }
void test_forward_inner(const string &e) { cout << "& " << e << endl; }
void test_forward_inner(string &&e) { cout << "&& " << e << endl; }
template <typename T>
void test_forward_wrapper(T &&arg) {
test_forward_inner(arg);
}
int main()
{
Example e;
test_forward_wrapper(e);
test_forward_wrapper(Example());
cout << endl;
string s("hello");
test_forward_wrapper(s);
test_forward_wrapper("hello");
return 0;
}
Here I tried to forward a lvalue and an rvalue from test_forward_wrapper()
to test_forward_inner()
. Running this program gives the output:
& example
& example
& hello
&& hello
For std::string
s, the desired inner function was called, but for my own class only the lvalue version was called. Only if I call std::forward
before passing the arguments to the inner function can the rvalue version get called.
What makes the difference here? As I know, according to the reference collapsing rules, when the wrapper was called with Example()
, an rvalue, T
would be deduced as Example
and arg
would have type Example &&
thus the rvalue version of the inner function should be called.
And, for other situations like the std::string
case here, the correct version of the inner function was called, then can we remove the std::forward
here? If not, what (maybe something bad) would happen?
Note that "hello"
is not std::string
, it's a const char[6]
. And test_forward_wrapper()
is a function template, the template argument T
will be deduced as char const (&)[6]
for it.
Inside test_forward_wrapper()
, test_forward_inner()
is called with const char[6]
, which need to be converted to std::string
at first. This is a temporary std::string
, i.e. a rvalue, preferred to be bound to rvalue reference , that's why test_forward_inner(string &&)
is called.
Passing an exact std::string
to test_forward_wrapper()
will get the same result.
test_forward_wrapper(std::string("hello"));
The difference is that in
test_forward_wrapper("hello");
"hello" here isn't a std::string
. It's a const char *
.
Change this to a
test_forward_wrapper(std::string("hello"));
And the result will be the same as the custom class's.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With