보편 참조(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 |