2
#include<iostream>

template<class T>
struct Foo
{
    T v_;

    Foo(T&& v):v_(std::forward<T>(v))
    {
        std::cout << "building Foo..\n";
    }
};


int main()
{
    int v;
    Foo<int> foo(v);

    std::cin.ignore();
}

visual c++ 2010 output :

error C2664: 'Foo<T>::Foo(T &&)' : cannot convert parameter 1 from 'int' to 'int &&'

Is it normal that I can't bind a lvalue to a rvalue reference ?

EDIT:

same thing for a function :

void f(int && v)
{

}
int v;
f(v); //won't compile

I'm a little bit confused because I think std::forward is usefull to detect if a method is called with a lvalue or a rvalue reference. But it seems that we can't bind any lvalue into rvalue reference... at least without template parameter but I don't understand it very well

Guillaume Paris
  • 10,303
  • 14
  • 70
  • 145
  • 4
    Yes, it's normal. Reference-collapsing rules would only apply if the constructor itself is a template. – ildjarn Jan 12 '12 at 19:48
  • @ildjarn: thanks, do you know the reason of that ? – Guillaume Paris Jan 12 '12 at 19:54
  • 2
    If reference-collapsing rules always applied to rvalue-reference syntax regardless of context then it wouldn't be possible to specifically denote a true rvalue-reference, which wouldn't be very useful. – ildjarn Jan 12 '12 at 19:55
  • @ildjarn: I have edited my post because I don't really understand your last comment – Guillaume Paris Jan 12 '12 at 20:07
  • 2
    In `void f(int && v)`, `v` is always an rvalue-reference. In `template void f(U && v)`, `v` can be an rvalue-reference or an lvalue-reference due to reference-collapsing rules. – ildjarn Jan 12 '12 at 20:08
  • 1
    [This](http://stackoverflow.com/questions/8526598/how-does-stdforward-work/8527373#8527373) might make it more clear to you. – Xeo Jan 12 '12 at 20:12
  • In your example, int i = 5; some_struct s2(i); I don't get why in ctor i is detect as int& and not as int, – Guillaume Paris Jan 12 '12 at 20:21
  • 1
    Because you're passing an lvalue, not an rvalue. – ildjarn Jan 12 '12 at 20:23
  • there is still something I don't understand...in the following example: int v = 5; f(int v); f(v); It seems I will pass 'v' as I pass 'i' in the previsous example,but here I have a int not a int&. So why 'i' (which was intially a int) become a int& when we try to bind it into a rvalue reference – Guillaume Paris Jan 12 '12 at 20:38
  • An lvalue can copied into a new value, as in `int v = 5; f(int v); f(v);`. However, an lvalue cannot be bound to an rvalue-reference. – ildjarn Jan 12 '12 at 20:42

1 Answers1

2

It's normal that calling a move constructor requires an r-value, not an l-value, since an l-value could be named after the move constructor runs, and using a moved-from value would evoke unintended behavior.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720