Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does std::move() not work without _Remove_reference?

_Remove_reference exists for, as you know, converting T& to T or T&& to T.

I made the following code in a playful mood, it doesn't work at all as I expected, but have no idea why.

template<class _Ty>
struct _Remove_reference
{   // remove reference
    typedef _Ty _Type;
    static void func(){ cout << "1" << endl; } 
};

// template<class _Ty>
// struct _Remove_reference<_Ty&>
// {    // remove reference
//  typedef _Ty _Type;
//  static void func(){ cout << "2" << endl; }
// };
// 
// template<class _Ty>
// struct _Remove_reference<_Ty&&>
// {    // remove rvalue reference
//  typedef _Ty _Type;
//  static void func(){ cout << "3" << endl; }
// };

template<class _Ty> inline
    typename _Remove_reference<_Ty>::_Type&&
    move(_Ty&& _Arg)
{   // forward _Arg as movable
    typename _Remove_reference<_Ty>::func();
    return ((typename _Remove_reference<_Ty>::_Type&&)_Arg);
}

int main(){
    int a1= 3;
    int&& a2 = move(a1); // can't convert the a1 to int&&
    return 0;
}

I guess it's all about reference collapsing rules, and template argument deduction but I am confused. my curiosity about this has to be shattered for me to sleep tight.

Thanks in advance.

like image 756
Dean Seo Avatar asked Nov 29 '11 07:11

Dean Seo


1 Answers

Given

template<class _Ty> inline
typename _Remove_reference<_Ty>::_Type&&
move(_Ty&& _Arg)

When you do move(a1), _Ty is deduced as int&. _Ty&& would thus still be int& due to the reference collapsing rules, so you need to remove the reference to get int before you can make it an rvalue reference.

This is a special case of the template argument deduction rules. If you have a function argument which is T&& where T is a template parameter, then if you pass an lvalue (i.e. a named object or an lvalue reference) to the function then T is deduced as X& where X is the type of the lvalue object. If you pass an rvalue (a temporary or an rvalue reference) to the function then T is just deduced as X.

e.g. move(a1) deduces _Ty to be int&, whereas move(42) deduces _Ty to be int.

BTW: I guess you took this code from your compiler's standard library --- names decorated with a leading underscore and a capital letter _Like _This are reserved for the compiler and standard library implementation.

like image 174
Anthony Williams Avatar answered Nov 14 '22 21:11

Anthony Williams