std :: move ()는 어떻게 값을 RValues로 전송합니까? 무엇인지 알고 있지만 std::move()VS2010에서 정의를 살펴보면 여전히

의 논리를 완전히 이해하지 못하고 std::move()있습니다.

처음에는 검색했지만 std::move()구조가 어떻게 작동하는지가 아니라 사용 방법에 대한 문서 만있는 것 같습니다 .

내 말은, 템플릿 멤버 함수가 무엇인지 알고 있지만 std::move()VS2010에서 정의를 살펴보면 여전히 혼란 스럽습니다.

std :: move ()의 정의는 다음과 같습니다.

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

저에게 가장 이상한 것은 (_Ty && _Arg) 매개 변수입니다. 왜냐하면 아래와 같이 함수를 호출하면

// main()
Object obj1;
Object obj2 = std::move(obj1);

기본적으로 다음과 같습니다.

// std::move()
_Ty&& _Arg = Obj1;

그러나 이미 알고 있듯이 LValue를 RValue 참조에 직접 연결할 수는 없기 때문에 이와 같아야한다고 생각합니다.

_Ty&& _Arg = (Object&&)obj1;

그러나 std :: move ()가 모든 값에 대해 작동해야하기 때문에 이것은 어리석은 일입니다.

그래서 이것이 어떻게 작동하는지 완전히 이해하고 있다고 생각합니다.이 구조체도 살펴 봐야합니다.

template<class _Ty>
struct _Remove_reference
{   // remove reference
    typedef _Ty _Type;
};

template<class _Ty>
struct _Remove_reference<_Ty&>
{   // remove reference
    typedef _Ty _Type;
};

template<class _Ty>
struct _Remove_reference<_Ty&&>
{   // remove rvalue reference
    typedef _Ty _Type;
};

불행히도 여전히 혼란스럽고 이해하지 못합니다.

이것이 C ++에 대한 기본적인 구문 기술이 부족하기 때문이라는 것을 알고 있습니다. 이러한 작업이 어떻게 철저하게 작동하는지, 인터넷에서 얻을 수있는 모든 문서를 환영하는 것 이상으로 알고 싶습니다. (당신이 이것을 설명 할 수 있다면 그것도 굉장 할 것입니다).



답변

이동 기능부터 시작합니다 (조금 정리했습니다).

template <typename T>
typename remove_reference<T>::type&& move(T&& arg)
{
  return static_cast<typename remove_reference<T>::type&&>(arg);
}

더 쉬운 부분부터 시작하겠습니다. 즉, 함수가 rvalue로 호출 될 때입니다.

Object a = std::move(Object());
// Object() is temporary, which is prvalue

우리 move는 다음과 같이 템플릿이 인스턴스화됩니다 :

// move with [T = Object]:
remove_reference<Object>::type&& move(Object&& arg)
{
  return static_cast<remove_reference<Object>::type&&>(arg);
}

이후 remove_reference변환 T&T또는 T&&T, 그리고 Object참조 아니며, 우리 최종 함수이다 :

Object&& move(Object&& arg)
{
  return static_cast<Object&&>(arg);
}

이제 궁금 할 것입니다. 캐스트가 필요한가요? 대답은 : 그렇습니다. 그 이유는 간단합니다. 명명 된 rvalue 참조 lvalue 처리되며 lvalue에서 rvalue 참조로의 암시 적 변환은 표준에 의해 금지됩니다.


movelvalue로 호출하면 다음과 같은 일이 발생합니다 .

Object a; // a is lvalue
Object b = std::move(a);

및 해당 move인스턴스화 :

// move with [T = Object&]
remove_reference<Object&>::type&& move(Object& && arg)
{
  return static_cast<remove_reference<Object&>::type&&>(arg);
}

다시 remove_reference변환 Object&하려면 Object우리가 얻을 :

Object&& move(Object& && arg)
{
  return static_cast<Object&&>(arg);
}

이제 까다로운 부분에 도달합니다. Object& &&even은 무엇 을 의미하며 어떻게 lvalue에 바인딩 할 수 있습니까?

완벽한 포워딩을 허용하기 위해 C ++ 11 표준은 다음과 같은 참조 축소에 대한 특수 규칙을 제공합니다.

Object &  &  = Object &
Object &  && = Object &
Object && &  = Object &
Object && && = Object &&

보시 다시피이 규칙에서 Object& &&실제로는 Object&lvalue 바인딩을 허용하는 일반 lvalue 참조 인을 의미 합니다.

따라서 최종 기능은 다음과 같습니다.

Object&& move(Object& arg)
{
  return static_cast<Object&&>(arg);
}

이는 rvalue를 사용한 이전 인스턴스화와 다르지 않습니다. 둘 다 인수를 rvalue 참조로 캐스팅 한 다음 반환합니다. 차이점은 첫 번째 인스턴스화는 rvalue로만 사용할 수있는 반면 두 번째 인스턴스는 lvalue로 작동한다는 것입니다.


remove_reference더 필요한 이유를 설명하기 위해이 기능을 사용해 보겠습니다.

template <typename T>
T&& wanna_be_move(T&& arg)
{
  return static_cast<T&&>(arg);
}

lvalue로 인스턴스화하십시오.

// wanna_be_move [with T = Object&]
Object& && wanna_be_move(Object& && arg)
{
  return static_cast<Object& &&>(arg);
}

위에서 언급 한 참조 축소 규칙을 적용하면 사용할 수없는 함수를 얻을 수 있습니다 move(간단히 말하면 lvalue로 호출하면 lvalue가 반환 됨). 이 기능은 식별 기능입니다.

Object& wanna_be_move(Object& arg)
{
  return static_cast<Object&>(arg);
}

답변

_Ty는 템플릿 매개 변수이며이 상황에서는

Object obj1;
Object obj2 = std::move(obj1);

_Ty는 “Object &”유형입니다.

이것이 _Remove_reference가 필요한 이유입니다.

더 같을 것입니다

typedef Object& ObjectRef;
Object obj1;
ObjectRef&& obj1_ref = obj1;
Object&& obj2 = (Object&&)obj1_ref;

참조를 제거하지 않았다면 우리가하는 것과 같을 것입니다.

Object&& obj2 = (ObjectRef&&)obj1_ref;

그러나 ObjectRef &&는 Object &로 축소되어 obj2에 바인딩 할 수 없습니다.

이 방법을 줄이는 이유는 완벽한 전달을 지원하기 위해서입니다. 이 문서를 참조하십시오 .