프로그래밍/C++

#67. 전달 참조 ( forwarding reference )

코딩하는상후니 2022. 7. 22. 22:41

 


 

*전달 참조 ( forwarding reference ) = 보편 참조 ( universal reference )
 
( template, auto 와 연관 )
=> std::forward 를 사용해야함.
 
std::move  :  r-value 를 반환. (즉, class<T>&& 로 캐스팅하는 용도 )

 

 

 

 

 

* 특수 템플릿 인자 유추 규칙
A&&                // -> A& 
    A&&&           // -> A& 
        A&&&       // -> A& 
            A&&&&  // -> A&&
template <typename T> 
void foo(T&& A);
A  :  좌측값 ( l-value ) 라면,
T&& + &A = T&&& = T&.
 
A  :  우측값 ( r-value ) 라면,
T&& + &&A  =  T&&&& = T&&.

 

 

 

 

 

* && 이 무조건 오른값 참조여야만 하나 ??
 
=> 형식 연역 ( type deduction = 타입추론 ) 할 때, 약간의 문제가 있을 수 있다.
ex) auto ,  template
void Test_RValueRef(Knight&& k)  => ( 오른값 참조 ) 
{ 
}

template<typename T> 
void Test_ForwardingRef(T&& param) => ( 전달참조 ) 
{ 
}

Knight k1;

Test_ForwardingRef(std::move(k1)); // (knight&&) 
Test_ForwardingRef(k1); // (knight&) 
auto&& k2 = k1; // (knight&) 
auto&& k3 = std::move(k1); // (knight&&)
=> 왼값을 넣으면 왼값참조  /  오른값을 넣으면 오른값참조로 동작
=> 둘 다 넣어질 수 있음.

 

 

 
 
template<typename T> 
void Test_templateRValueRef(const T&& param) // const 
{ 
} 
//Test_templateRValueRef(k1); => ERROR 
Test_templateRValueRef(std::move(k1)); // (knight&&)
=> const 를 붙이면 오른값 참조
 
 
 
 

 

 

*왜 Lvalue, Rvalue 두 가지를 같이 받을 수 있는 전달참조를 따로 만들었을까 ??
Rvalue / Lvalue 따로 만들면 안되었나??
 
=> 효율성 문제.
l-value / r-value 를 구분해야한다면
템플릿에서 여러 타입을 정의할 시(ex. T1, T2... ), 함수를 여러 개 만들어야 한다.
( T1&& A, T2&& B ) 만 해도 4개를 만들어야한다.
 
 
 

 

*l-value / r-value 가 같이 들어오는 상황을 어떻게 처리할까 ??
Knight k1;
Knight& k4 = k1; 
Knight&& k5 = std::move(k1);

Test_RValueRef(k5); // ERROR, 
Test_ForwardingRef(k5); // (Knight&) 
Test_ForwardingRef(std::move(k5)); // (Knight&&)
=> k5 처럼 r-value 가 변수로 선언되면 타입은 r-value 가 맞지만, k5 자체는 l-value 가 됨.
따라서, 한번 더 std::move 를 해주어야 r-value 참조로 들어간다.
 

 

 

 

 
* std::forward
template <class S> 
S&& forward(typename remove_reference<S>::type& a) noexcept { 
  return static_cast<S&&>(a); 
}
void TestCopy(Knight k) {}

template<typename T> 
void Test_ForwardingRef(T&& param) 
{ 
	TestCopy(std::forward<T>(param)); 
	// 왼값 참조라면 복사 => TestCopy(param); 
	// 오른값 참조라면 이동  => TestCopy(std::move(param)); 
}
=> 만약, param 에 & 타입이 들어왔으면 함부로 move 하면 안된다.
왜냐하면 &, && 둘 다 들어오는 상황이므로.
=> std::forward 를 사용해 두 가지 경우를 한번에 처리할 수 있다.
 
 
 
 

 

참고 링크

https://modoocode.com/189

 

 

본 내용은 인프런의 루키스님 강의를 듣고 정리한 내용입니다.

 

 

 

'프로그래밍 > C++' 카테고리의 다른 글

#69. c++ 스마트 포인터 ( smart pointer )  (0) 2022.07.23
#68. 람다 (lambda)  (0) 2022.07.22
#66. 오른값참조 ( rvalue reference )  (0) 2022.07.22
#65. enum class & override & final  (0) 2022.07.22
#64. using  (0) 2022.07.22