728x90
완벽 전달(Perfect Forwarding)
- &을 두 번 사용하면 && -> 오른 값 참조이다.
- 그러면, 함수의 인자로 오른 값 참조 타입을 받을 때, 이를 구분하기 위해서 매 번 2개씩 만들어야 할까?
void Func(Person& p) { }
void Func(Person&& p) { }
일반적인 함수에서는 그냥 2개씩 만들어주면 된다. 복사 생성자와 이동 생성자를 만들어주는 것과 비슷하다.
하지만, 형식 연역(auto, template)이 들어가는 경우에는 컴파일러가 전달되는 타입의 추론이 이상해진다.
다음 코드를 보자.
템플릿 함수인 Foo는 인자로 오른 값 참조를 받는데, 템플릿이기 때문에 일단 아무 타입이나 받을 수 있다.
여기에 L-Value와 R-Value를 각각 넣어 출력하는 함수를 호출해 보면, 각각 다르게 나와야 정상이지만, 둘 다 L-Value로 출력되는 것을 확인할 수 있다.
struct X {};
void Func(X& x) { std::cout << "L-Value" << "\n"; }
void Func(X&& x) { std::cout << "R-Value" << "\n"; }
template<typename T>
void Foo(T&& t) { Func(t); }
int main()
{
// L-Value 전달
X x;
Foo(x);
// R-Value 전달
Foo(X());
}

std::forward
이를 위해서 STL에서는 std::forward라는 함수를 제공한다.
std::forward 함수는 L-Value는 L-Value로, R-Value는 R-Value로 형변환할 수 있다.
이는 특히 템플릿 프로그래밍에서 사용하면 유용하다.
move 사용
그냥 다 move로 밀어버리면, 둘 다 R-Value로 인식해서 동작한다.
하지만, 인자로 들어간 L-Value는 R-Value로 형변환되어 제거된다.
struct X {};
void Func(X& x) { std::cout << "L-Value" << "\n"; }
void Func(X&& x) { std::cout << "R-Value" << "\n"; }
template<typename T>
void Foo(T&& t) { Func(std::move(t)); }
int main()
{
// L-Value 전달
X x;
Foo(x);
// R-Value 전달
Foo(X());
}

forward 사용
forward를 사용하면, 내부에서 L-Value와 R-Value를 처리하여 정상적으로 출력된다.
struct X {};
void Func(X& x) { std::cout << "L-Value" << "\n"; }
void Func(X&& x) { std::cout << "R-Value" << "\n"; }
template<typename T>
void Foo(T&& t) { Func(std::forward(t)); }
int main()
{
// L-Value 전달
X x;
Foo(x);
// R-Value 전달
Foo(X());
}

728x90
'📕Programming > 📝C/C++' 카테고리의 다른 글
| [C / C++] 인라인 함수 (in-line function) (0) | 2023.12.28 |
|---|---|
| [C / C++] 스마트 포인터(Smart Pointer) (0) | 2023.12.06 |
| [C / C++] 오른 값 참조(R-Value Reference)와 Move Semantics (0) | 2023.12.04 |
| [C / C++] delete (삭제된 함수) (0) | 2023.12.01 |
| [C / C++] enum class (0) | 2023.11.29 |