Jul 7, 2016 at 4:22pm UTC
Let's have a function called Y that overloads:
1 2 3 4 5
void Y(int & lvalue)
{ cout << "lvalue!" << endl; }
void Y(int && rvalue)
{ cout << "rvalue!" << endl; }
Now, let's define a template function that acts like std::forward
1 2 3 4 5
template <class T>
void f(T&& x)
{
Y( static_cast <T&&>(x) ); // Using static_cast<T&&>(x) like in std::forward
}
Now look at the main()
1 2 3 4 5 6 7
int main()
{
int i = 10;
f(i); // lvalue >> T = int&
f(10); // rvalue >> T = int&&
}
As expected, the output is
Now come back to the
template function f() and replace
static_cast <T&&>(x)
with this
static_cast <T>(x)
Let's see the output:
It's the same!
If we follow the
Reference Collapsing rules, this actually makes sense
& + & = &
& + && = &
&& + & = &
&& + && = &&
----------------------------------------------------------------------
[1] When we call f(i) where
T = int& this happens
(a) Our
static_cast <T&&>
becomes
static_cast <int & &&>(x)
which becomes
static_cast <int &>(x)
(b) Our
static_cast <T>
becomes
static_cast <int &>(x)
[2] When we call f(10) where
T = int&& this happens
(a) Our
static_cast <T&&>
becomes
static_cast <int &&>(x)
(b) Our
static_cast <T>
becomes
static_cast <int >(x)
Question: since both the casts produce the same result, why was std::forward made to return a static_cast<T&&> conversion instead of static_cast<T>?
Last edited on Jul 7, 2016 at 5:52pm UTC
Jul 8, 2016 at 3:07am UTC
in the rvalue case, T deduces to int, not int&&. And then static_cast<T> creates a new object instead of forwarding: it makes an extra call to the copy constructor and then to the destructor of T, while static_cast<T&&> does not (try replacing int with a class with noisy special member functions)
Last edited on Jul 8, 2016 at 3:11am UTC
Jul 8, 2016 at 9:22am UTC
Last edited on Jul 8, 2016 at 9:22am UTC