보편 참조(universal reference)가 C++ 17 이후부터, 전달 참조 (forwarding reference)로 변경되었다.

1. '&'를 두 번 쓰면 무조건 오른값 참조일까?

class Knight
{
public:

    Knight (){} // 기본 생성자
    Knight(const Knight&){} // 복사 생성자
    Knight (Knight&&){} // 이동 생성자

public:

    int _hp = 100;
};

void Test_RValueRef(Knight&& k){}

int main()
{
    Knight k1;

    Test_RValueRef(move(k1));


}

여기에서 어떤 타입 T를 받는 함수를 만들어 보자.

 

template<typename T>
void Test_ForwardingRef(T&& param)
{

}

int main()
{
    Knight k1;

    Test_RValueRef(move(k1));

    Test_ForwardingRef(move(k1));
}

오른값 참조도 오류 없이 작동한다.

 

int main()
{
    Knight k1;

    Test_RValueRef(move(k1));

    Test_ForwardingRef(k1);
    Test_ForwardingRef(move(k1));
    
    auto&& k2 = k1;       //왼값 참조
    auto&& k3 = move(k1); //오른값 참조
}

 

이렇게 &&를 사용하여 오른값 참조를 하려고 했는데도 왼값 참조가 잘 작동하는 것을 알 수 있다.

 

즉, 형식 연역이 발생하는 상황에서 왼값 참조와 오른값 참조로 동작하는 것을 전달 참조라고 한다.

 

2. 전달 참조를 사용하는 이유?

원래는 각 참조를 사용하겠다고 하면 왼값 참조도 만들어야 하고, 오른값 참조도 만들어야 했다.

만약의 함수의 인자가 1개가 아니라 2개로 늘어난다면, 늘어나는 수 만큼 함수를 만들어야 한다.

따라서 전달 참조를 사용하면 코드를 더 단순하게 만들 수 있게 된다.

 

3. 전달 참조 구별하는 방법?

    Knight& k4 = k1; // 왼값 참조
    Knight&& k5 = move(k1); // 오른값 참조?

    Test_RValueRef(k5); // 오류 발생

 

오른값은 단일식에서 벗어나면 사용이 불가능하다.

오른값 참조는 오름값만 참조할 수 있는 타입이다.

위에서 k5는 k1을 오른값으로 캐스팅해서 받았기 때문에 오른값이라고 생각할 수도 있지만..

k5 자체는 오른값이 아니라 왼값이다.

    Test_RValueRef(move(k5));

여기에서 아래와 같은 문법을 사용하면 함수에 왼값이 들어가면 복사, 오른값이 들어가면 이동이 일어나게 할 수 있다.

template<typename T>
void Test_ForwardingRef(T&& param)
{
    Test_Copy(std::forward<T>(param));
}

 

'기초 C++ 스터디 > 모던 C++' 카테고리의 다른 글

10-10. 스마트 포인터  (0) 2023.06.26
10-9. 람다(lambda) 표현식  (0) 2023.06.22
10-7. 오른값 참조(Rvalue Reference)  (0) 2023.06.22
10-6. override, final  (0) 2023.06.20
10-5. delete - 삭제된 함수  (0) 2023.06.20