Language/C++

C++ 11 :: Perfect Forwarding (퍼펙트 포워딩)

VallistA2015. 2. 14. 18:59

퍼펙트 포워딩을 알기 위해서는 먼저 C++ 포워딩에 대해 알아야 한다.


먼저 C++ 포워딩의 문제를 보도록 하자.


1.



a 라는 변수를 전달하며, a 라는 변수는 1이라는 상수 값(R-Value)를 가진 L-Value이다.
따라서 ForwardThis() 라는 함수가 받아야 할 값은 파라미터 형식인 레퍼런스 타입의 정수 타입으로 변환될 수 있으며 C++ 표준 문법으로 좀 더 정확히 말해보자면, FowardThis() 함수가 받아야 할 파라미터 형식은 L-Avlue 레퍼런스 타입인데, a는 L-Value 이므로 당연히 ForwardThis 함수에 파라미터로 넘겨줄 수 있다.

하지만 ForwardThis(1); 에서는 의미상 같지만 에러가 난다.

에러를 요약하자면 int를 int&로 바꿀 수 없다고 나버린다.
즉 전에 언급한 것 처럼 L-Value 레퍼런스는 오른쪽 값으로 L-Value 만 받을 수 있다.
하지만 1은 L-Value가 아니라 R-Value이다. 컴파일 에러가 발생할 수 밖에 없다.

이러한 포워딩 문제를 해결하려면 함수 오버로딩으로 해결하는 방법이 있다.

2.



이번에는 에러가 발생하지 않는다. 왜냐하면 각각의 함수 오버로딩을 부르기 때문이다.

.a에 1을 저장해서 보내는 것과 1을 바로 전달하는 것은 어차피 같은거 아닌가 라는 의문이 생길텐데

의미상으론 같지만 컴파일러 내부적으로는 엄격하게 L-Value와 R-Value, 정확히 말하면 해당 표현힉의 const를 확인했던 것이다.

그래도 때마다 필요한 파라미터 타입을 오버로딩해서 사용하면 되잖냐고 생각할 수 있는데, 물로 상관은 없다 하지만 함수 파라미터가 하나 아닌 두개나 세개인 상황은 애매해진다.


자 그러면 C++ R-Value 레퍼런스를 이용한 퍼펙트 포워딩을 해보도록 하자.


근데 이게 예상외로 간단하다. ForwardThis() 함수의 파라미터 타입을 L-Value 레퍼런스인 int & 에서 R-Value 레퍼런스인 int&& 바꾸는 것으로 해결할 수 있다.


3.



실제로 C++ 11 전에는 레퍼런스 변수를 다시 레퍼런스 변수로 지정하는 것은 에러가 발생하는 사항이었다. 그러나 C++ 11 에서는 다음과 같은 레퍼런스 붕괴 법칙 (Reference Collapsing Rule)을 도입하게 된다.


1. T&의 &의 의미 : T& (L-Value 레퍼런스의 L-Value 레퍼런스는 L-Value 레퍼런스)

2. T&의 &&의 의미 : T&(L-Value 레퍼런스의 R-Value 레퍼런스는 L-Value 레퍼런스)

3. T&&의 &의 의미 : T&(R-Value 레퍼런스의 L-Value 레퍼런스는 L-Value 레퍼런스)

4. T&&의 &&의 의미 : T&&(R-Value 레퍼런스의 R-Value 레퍼런스는 R-Value 레퍼런스)


1. ForwardThis(int&& i) 함수가 L-Value 타입의 인자 i에 대해 호출되면, 위 규칙2에 의거해 i는 L-Value로 추론함.

2. ForwardThis(int&& i) 함수가 R-Value 타입의 인자 i에 대해 호출되면, i는 자연스럽게 R-Value로 추론


C++ 11으로 확정되기 전인 C++0x 표준에서는, 위 main() 함수 안 코드를 전혀 바꾸지 않아도 문제가 없었다. 따라서 C++0x 표준을 준수한 Visual C++ 2010 베타 버전까지는 다음 코드가 컴파일 잘 된다.


4.



std::move() 함수는 C++ 11에서 새롭게 도입된 함수이다.

Move Semantics를 지원하기 위해 도입했고, 파라미터로 전달받는 객체의 내용을 전달해줄 함수가 복사가 아닌 이동하기 위한 함수인데 이를 위한 std::move() 함수는 인자로 받은 변수를 R-Value로 바꿔준다. 실제로 함수 내부를 살펴보면 단지 R-Value로 정적 타입 변환 (static type cast) 하도록 되어있다.

'Language > C++' 카테고리의 다른 글

C++ :: RTTI (Run-Time Type Information)  (2) 2015.05.29
C++ :: C++ Style Cast (C++ 스타일 캐스트)  (0) 2015.04.02
C++ 11 :: Move Semantics  (0) 2015.02.14
C++ 11 :: R-Value Reference  (0) 2015.02.14
C++ 11 :: static_assert Keyword  (0) 2015.02.14

댓글

VallistA

병특이 끝나서 게임에서 웹으로 스위칭한 프로그래머.
프로그래밍 정보등을 공유합니다.
현재는 이 블로그를 운영하지 않습니다.
vallista.kr 로 와주시면 감사하겠습니다!

자고 싶습니다. ㅠㅠ

Github      :: 링크

궁금한점 문의 주시면 답변드리도록 하겠습니다

VISITED

Today :

Total :

SNS

  • 페이스북아이콘
  • 카카오톡아이콘
  • 트위터아이콘

Lately Post

Lately Comment