의 논리를 완전히 이해하지 못하고 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 참조로의 암시 적 변환은 표준에 의해 금지됩니다.
move
lvalue로 호출하면 다음과 같은 일이 발생합니다 .
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에 바인딩 할 수 없습니다.
이 방법을 줄이는 이유는 완벽한 전달을 지원하기 위해서입니다. 이 문서를 참조하십시오 .