* 정의

 

보편 참조를 받는 함수 템플릿에서 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

+ Recent posts