* 정의
보편 참조를 받는 함수 템플릿에서 T에 따라 매개 변수는 Type& && (T가 Type&일 때)와 같은 형태가 나타날 수 있다. 이때 Type& && 는 Type&으로 간주된다.
원래 참조에 대한 참조가 위법이지만 템플릿 인스턴스화와 같은 특정 문맥에서는 참조에 대한 참조가 허용된다. 또한 이러한 경우 참조 축약의 규칙이 적용된다. (Type& && => Type& 등)
* 동작 방식
- 참조 축약 규칙
특정 문맥(템플릿 인스턴스화 등)에서 발생하는 참조 축약의 규칙은 다음과 같다.
| 참조 유형 | 설명 | 평가 |
| Type& & | 왼값 참조에 대한 왼값 참조 | Type& |
| Type& && | 왼값 참조에 대한 오른값 참조 | Type& |
| Type&& & | 오른값 참조에 대한 왼값 참조 | Type& |
| Type&& && | 오른값 참조에 대한 오른값 참조 | Type&& |
- 참조 축약을 이용한 std::forward 의 동작 원리
std::forward가 정상적으로 동작하는 이유는 참조 축약 덕분이라고 할 수 있다.
간단히 예시를 들어보면 다음과 같다.
template<typename T>
T&& Forward(std::remove_reference_t<T>& param)
{
return static_cast<T&&>(param);
}
template <typename T>
void Function(T&& param)
{
FunctionImpl(Forward<T>(param));
}
Function에 전달된 인수 param가 왼값인지 오른값인지에 대한 정보가 형식 매개변수 T에 부호화된다.
T가 비참조 형식이면 오른값이고 왼값 param을 오른값으로 캐스팅한다. 상황에 따라 캐스팅되는 형식을 표로 나타내면 다음과 같다.
| T | param | 전달된 인수 타입 | Forward 캐스팅 |
| Type | Type&& | 오른값 | Type&&(오른값) |
| Type& | Type& | 왼값 | Type& && => Type&(왼값) |
- auto 변수에 대한 형식연역에서의 참조 축약
auto 변수의 형식 연역은 템플릿의 형석 연역과 본질적으로 같기 때문에 참조 축약이 일어난다.
template <typename T>
void Function(T&& param)
{
// ...
}
void AutoTest(void)
{
int a = 3;
// int&로 연역 // int& && -> int&
Function(a);
// 템플릿 연역과 본질적으로 같다. 따라서 int&로 연역 // int& && -> int&
auto&& b = a;
}
- typedef와 별칭 선언에서의 참조 축약
typedef와 별칭 선언에서 평가되는 도중에 참조에 대한 참조가 발생하면 참조 축약이 끼어들어서 참조에 대한 참조를 제거한다.
template <typename T>
class Widget
{
public:
typedef T&& RValueRefToT1;
using RValueRefToT2 = typename T&&;
};
void DefTest(void)
{
// int& // int& && -> int&
Widget<int&>::RValueRefToT1;
// int& // int& && -> int&
Widget<int&>::RValueRefToT2;
// int&&
Widget<int>::RValueRefToT1;
// int&&
Widget<int>::RValueRefToT2;
}
- decltype에서의 참조 축약
컴파일러가 decltype에 관여갛는 형식을 분석하는 도중에 참조에 대한 참조가 존재하면 참조 축약이 발생한다.
'C++' 카테고리의 다른 글
| 람다(Lambda) (0) | 2022.04.11 |
|---|---|
| 완벽 전달(Perfect forwarding)의 실패 (0) | 2022.03.31 |
| 보편 참조에 대한 중복적재 대안 (0) | 2022.03.31 |
| 보편 참조와 오른값 참조 (0) | 2022.03.27 |
| std::forward (0) | 2022.03.27 |