C++ why does passing an lvalue to a move constructor work for templates?

c++, c++11, templates, visual-studio-2012

Solution

Yes. In the case of a template function, the compiler deduces the template argument `T` such that it matches the argument given.

Since `someData` is in fact an lvalue, `T` is deduced as `SomeData &`. The declaration of `Function`, after type deduction, then becomes

void Function(SomeData & &&)

and `SomeData & &&`, following the rules for reference collapsing, becomes `SomeData &`.

Hence, the function argument `someData` becomes an lvalue-reference and is passed as such to the initialization of `localData`. Note that (as @aschepler pointed out correctly) `localData` is declared as `T`, so it is itself a reference of type `SomeData &`. Hence, no copy construction happens here – just the initialization of a reference.

If you want `localData` to be an actual copy, you would have to turn the type from `SomeData &` into `SomeData`, i.e. you would have to remove the `&` from the type. You could do this using `std::remove_reference`:

template<class T>
void Function(T &&someData)
{
   /* Create a copy, rather than initialize a reference: */
    typename std::remove_reference<T>::type localData(someData);
    localData.Print();
}

(For this, you'd have to `#include <type_traits>`.)

Problem

I have this code, which doesn't compile, which is expected. This is the error: `an rvalue reference cannot be bound to an lvalue` ``` class SomeData { public: vector<int> data; SomeData() { cout << "SomeData ctor" << endl; data.push_back(1); data.push_back(2); data.push_back(3); } SomeData(const SomeData &other) { cout << "SomeData copy ctor" << endl; data = other.data; } SomeData(SomeData &&other) { cout << "SomeData move ctor" << endl; data = move(other.data); } ~SomeData() { cout << "SomeData dtor" << endl; } void Print() const { for(int i : data) cout << i; cout << endl; } }; void Function(SomeData &&someData) { SomeData localData(someData); localData.Print(); } int main(int argc, char *argv[]) { SomeData data; Function(data); // ERROR data.Print(); return 0; } ``` But, when I turn `Function()` into a template, it works fine, and uses the copy constructor of `SomeData` instead. ``` template<class T> void Function(T &&someData) { T localData(someData); // no more error localData.Print(); } ``` Is this standard C++ behaviour? I've noticed that visual studio tends to be more forgiving when it comes to templates, so I am wondering if I can expect this same behaviour from all compliant C++11 compilers.

Original source

Related problems