본문 바로가기
Script/Modern C++

[Modern C++] Chapter 09. 전달 참조 (forwarding reference)

by song.ift 2023. 5. 23.

GitHub : https://github.com/developeSHG/Modern-C/blob/a30dc0a22e2afcdb8ae81e9ca9e3f46fb125ab66/Modern%20C%2B%2B/Modern%20C%2B%2B/%EC%A0%84%EB%8B%AC%20%EC%B0%B8%EC%A1%B0%20(forwarding%20reference).cpp 

 

GitHub - developeSHG/Modern-C: Modern C++

Modern C++. Contribute to developeSHG/Modern-C development by creating an account on GitHub.

github.com

 

 


 

 

오른값이라는 개념으로 인해 template이나 auto같이 형식을 연역하는 부분에 있어 오른값이라는 새롭게 구분해야 하는게 생겼는데, 이걸 오른값전용 rvalue_template 같은식으로 따로 만들지 않고 조건에 따라서는 한 번에 만들 수 있게 해주고,

들어온 값이 오른값인지를 std::forward() 의 반환값으로 오른값/왼값을 반환해서 판별할 수 있게 해줬다. 

 

여기서 오른값인지 왼값인지 전달해 주는게 전달참조.

 

#include <iostream>

using namespace std;

// 주제 : 전달 참조 (forwarding reference)

class Knight
{
public:
	Knight() { cout << "기본 생성자" << endl; }
    Knight(const Knight&) { cout << "복사 생성자" << endl; }
    Knight(Knight&&) noexcept { cout << "이동 생성자" << endl; }
}

void Test_RValueRef(Knight&& k) // 오른값 참조
{

}

void Test_Copy(Knight k)
{

}

template<typename T>
void Test_ForwardingRef(T&& param)	// 전달 참조 : 왼값을 넣어줬으면 왼쪽 참조로 작동, 오른값을 넣어줬으면 오른쪽 참조
{
	Test_Copy(std::forward<T>(param));
}

int main()
{
	// 보편 참조(universal reference)로 불렸는데
    // C++17로 넘어오면서 전달 참조(forwarding reference) 라고 부름
    
    // &&		&를 두 번 -> 오른값 참조
    
    Knight k1;
    
    Test_RValueRef(std::move(k1)); rvalue_cast
    
    // &&는 무조건 오른값 참조일까?
    Test_ForwardingRef(k1);				// 왼값 참조
	Test_ForwardingRef(std::move(k1));	// 오른값 참조
    
    auto&& k2 = k1;				// 왼값 참조
    auto&& k3 = std::move(l1);	// 오른값 참조
    
    // 공통점 : 형식 연역 (type deduction)이 일어날 때 (template, auto)
    
    // 전달 참조를 구별하는 방법
    // --------------------------------------
    
    Knight& k4 = k1; // 왼값 참조
    Knight&& k5 = std::move(k1); // 오른값 참조
    
    // 오른값 : 왼값이 아니다 = 단일식에서 벗어나면 사용 X
    // 오른값 참조 : 오른값만 참조할 수 있는 참조 타입
    Test_RValueRef(k5);
    // 위의 함수는 k5가 인수로 허용되지 않는다.
    // 왜냐하면 k5는 "오른값 참조"이지, "오른값" 이 아니기 때문이다.
    // "오른값"은 단일식에서 벗어나면 사용이 불가한데 k5 자체는 오른값 참조일 뿐, 재사용이 가능하기 때문이다.
    Test_RValueRef(std::move(k5)); // 그래서 다시 오른값을 추출.
    
    // 그래서 Test_ForwardingRef 의 인수로 std::move(k5)를 해도
    // Test_ForwardingRef 내부 함수에선 param은 오른값 참조일뿐, 왼값이기 때문에,
    // 또 Test_Copy의 인수에 std::move로 오른값으로 추출해줘야 하는 문제가 발생한다.
    
    // 그래서 왼값 참조라면 복사
    // => Test_Copy(param)
    // 오른값 참조라면 이동
    // => Test_Copy(std::move(param));
    // 이 참조의 종류를 체크를 해주는 방법이 [전달참조]
    // Test_Copy(std::forward<T>(param));
    
    Test_ForwardingRef(k1); // 복사 방식
    Test_ForwardingRef(std::move(k1)); // 이동 방식
    
	return 0;
}

댓글