"진리가 너희를 자유롭게 하리라"라는 말이 있긴 하지만, 상황에 따라서는 잘 선택된 거짓말 역시 진리만큼이나 우리를 자유롭게 합니다. 이번 항목이 그런 거짓말에 해당합니다. 그런데 우리가 다루는 것은 소프트웨어이므로, "거짓말"이라는 단어는 피하기로 합시다. 대신, 이번 항목이 하나의 "추상(abstraction)"을 함의한다고 말하는 것이 좋겠습니다.
어떤 형식 T에 대한 오른 값 참조를 선언할 때에는 T&&라는 표기를 사용합니다. 그래서 소스 코드에 "T&&"를 발견했다면 그것이 오른 값 참조라고 가정하는 것은 당연해 보입니다. 그러나 안타깝게도 그렇게 단순하지는 않습니다.
void f(Widget&& param); // 오른값 참조
Widget&& var1 = Widget(); // 오른값 참조
auto&& var2 = var1; // 오른값 참조 아님
template<typename T>
void f(std::vector<T>&& param); // 오른 값 참조
template<typename T>
void f(T&& param); // 오른 값 참조 아님
사실 "T&&"에는 서로 다른 두 가지 의미가 있습니다. 하나는 물론 오른 값 참조입니다. 그런 참조는 예상한 그대로 행동합니다. 즉, 그런 의미의 오른 값 참조는 오직 오른 값에만 묶이며, 일차적인 존재의 이유(raison detre)는 이동의 원본이 될 수 있는 객체를 지정하는 것입니다.
"T&&"의 또 다른 의미는 오른값 참조 또는 왼 값 참조 중 하나라는 것입니다. 그런 참조는 소스 코드에서는 오른 값 참조(즉, "T&&")처럼 보이지만, 때에 따라서는 왼 값 참조(즉, "T&")인 것처럼 행동합니다. 이러한 이중성 덕분에, 이런 참조는 오른 값에 묶을 수도 있고(오른 값 참조처럼) 왼 값에 묶을 수도 있습니다(왼 값 참조처럼). 더 나아가서, 이런 참조는 const 객체에 묶을 수도 있고 비 const 객체에 묶을 수도 있으며, 마찬가지로 volatile 객체에 묶을 수도 있고 volatile 객체에 묶을 수도 있습니다. 심지어 const이자 volatile인 객체에도 묶을 수 있습니다. 즉, 거의 모든 것에 묶을 수 있는 것입니다. 이처럼 전례 없이 유연한 참조이니만큼, 번듯한 이름을 붙여 주어야 마땅합니다. 나는 이런 참조를 보편 참조(universal reference)라고 부릅니다.
(* Chapter (25)에서 설명하듯이, 보편 참조에는 거의 항상 std::forward를 적용해야 합니다. 그런 이유로 이 가오자에서는 C++ 공동체의 일부 구성원들은 보편 참조를 forwarding reference(전달 참조)라고 부르기 시작했습니다.)
보편 참조는 두 가지 문맥에서 나타납니다. 가장 흔한 것은 함수 템플릿 매개변수 입니다. 앞에 나온 예제 코드 중 다음 부분이 그러한 문맥에 해당합니다.
template<typename T>
void f(T&& param); // param은 보편 참조
'컴퓨터과학' 카테고리의 다른 글
C++ (23-2) std::move와 std::forward를 숙지할 것 (0) | 2020.06.29 |
---|---|
C++ (23-1) std::move와 std::forward를 숙지할 것 (0) | 2020.06.28 |
C++ (22-4) Pimpl 관용구를 사용할 떄에는 특수 멤버 함수들을 구현 파일에서 정의할 것 (0) | 2020.06.26 |
C++ (22-3) Pimpl 관용구를 사용할 떄에는 특수 멤버 함수들을 구현 파일에서 정의할 것 (0) | 2020.06.25 |
C++ (22-2) Pimpl 관용구를 사용할 떄에는 특수 멤버 함수들을 구현 파일에서 정의할 것 (0) | 2020.06.24 |