C++11에서 도입된 전달 참조(Forwarding Reference)는 왼값(lvalue)과 오른값(rvalue)을 모두 처리할 수 있는 유연한 참조입니다.
이 문법은 템플릿 함수와 auto&&에서만 적용되며, std::forward를 활용하면 완벽한 전달(Perfect Forwarding)이 가능합니다.
✅ 전달 참조(T&&) → 왼값 참조 또는 오른값 참조로 동작 가능
✅ std::forward<T> → 원본 타입이 왼값이면 복사, 오른값이면 이동을 수행
이 문서에서는 전달 참조와 std::forward의 원리를 예제 코드와 함께 상세히 분석하겠습니다.
Knightclass Knight
{
public:
Knight() { cout << "기본 생성자" << endl; }
Knight(const Knight&) { cout << "복사 생성자" << endl; }
Knight(Knight&&) noexcept { cout << "이동 생성자" << endl; }
};
✅ Knight 클래스
"기본 생성자" 출력 "복사 생성자" 출력 (객체가 복사될 때 호출됨) "이동 생성자" 출력 (객체가 이동될 때 호출됨) void Test_RValueRef(Knight&& k)
{
}
✅ 오른값 참조(rvalue reference) 함수
rvalue)만 받을 수 있음 → Test_RValueRef(k1); 컴파일 에러 발생 std::move(k1)를 사용하여 강제로 오른값으로 캐스팅하면 전달 가능 void Test_Copy(Knight k)
{
}
✅ 복사 전달 함수
Knight 객체를 값(pass-by-value)으로 전달하여 복사 생성자가 호출됨 std::move 또는 std::forward를 고려해야 함 template<typename T>
void Test_ForwardingRef(T&& param)
{
Test_Copy(std::forward<T>(param)); // 왼값이면 복사, 오른값이면 이동
Test_Copy(param); // 항상 복사
Test_Copy(std::move(param)); // 항상 이동
}
✅ 전달 참조(Forwarding Reference) 함수
T&& param이 전달 참조로 동작하며 왼값과 오른값을 모두 처리 가능 std::forward<T>(param) param이 왼값 참조이면 복사 param이 오른값 참조이면 이동 std::move(param) //template<typename T, typename T2>
//void Test_ForwardingRef(T&& param, T2&& param2)
//{
// //TODO
//
//}
//void Test_ForwardingRef(const T&& param) // 오른값 참조로 동작
//{
//
//}
✅ 여러 개의 전달 참조 매개변수 처리
const T&& param → 이 경우 전달 참조가 아니라 오른값 참조로 동작 main() 함수 분석int main()
{
✅ 프로그램 실행의 시작점.
Knight k1;
//Test_RValueRef(k1); // 에러: 오른값 참조 함수에 왼값 전달 불가
Test_RValueRef(std::move(k1)); // 이동 가능
✅ 오른값 참조 함수 실행
Test_RValueRef(k1); → 컴파일 오류 (왼값을 오른값 참조 함수에 전달 불가) Test_RValueRef(std::move(k1)); → std::move를 사용하면 정상적으로 이동 가능 T&&)와 auto&& //Test_ForwardingRef(k1); // Knight의 왼값 참조
//Test_ForwardingRef(std::move(k1)); // Knight의 오른값 참조
auto&& k2 = k1;
auto&& k3 = std::move(k1);
✅ 전달 참조의 특성
Test_ForwardingRef(k1); → 왼값 참조로 전달 Test_ForwardingRef(std::move(k1)); → 오른값 참조로 전달 auto&&는 전달된 값의 타입에 따라 왼값 참조 또는 오른값 참조로 자동 추론 auto&& k2 = k1; → k2는 Knight& (왼값 참조) auto&& k3 = std::move(k1); → k3는 Knight&& (오른값 참조) Knight& k4 = k1; // 왼값 참조
Knight&& k5 = std::move(k1); // 오른값 참조
//k5 자체는 왼값
Test_RValueRef(std::move(k5)); // 이동 가능
✅ std::move 사용
k5는 Knight&&로 선언되었지만 변수 자체는 왼값으로 간주됨 std::move(k5); → k5를 오른값으로 변환하여 이동 가능 Test_ForwardingRef(k1); // 왼값 전달
Test_ForwardingRef(std::move(k1)); // 오른값 전달
✅ 전달 참조(T&&) 활용
k1을 전달하면 왼값 참조로 추론되어 복사 생성자 호출 std::move(k1)을 전달하면 오른값 참조로 추론되어 이동 생성자 호출