1 분 소요

1. move

template <class _Ty>
constexpr remove_reference_t<_Ty>&& move(_Ty&& _Arg) noexcept {
    return static_cast<remove_reference_t<_Ty>&&>(_Arg);
}

1-1. 인자값

move(_Ty&& _Arg) noexcept

들어오는 input값을 T&& Universal Reference로 받고 있다

  • T > T&
  • T& > T&
  • T&& > T&& 즉 lvalue든 rvalue든 상관없이 둘 다 받겠다는 뜻

1-2. 함수내부

return static_cast<remove_reference_t<_Ty>&&>(_Arg);

remove_reference_t?

들어온 타입의 reference 형을 지워주는 역할

type이 lvalue든 rvalue든 reference를 지워서 일반자료형으로 만든 다음에 rvalue(&&) 형으로 static_cast를 시키므로 무조건 rvalue로서의 캐스팅 역할을 수행하는 것

1-3. 반환 타입

constexpr remove_reference_t<_Ty>&&

constexpr로 컴파일타임 때 동작하도록 함수를 상수화 위와 같이 reference를 지우고 &&를 추가하면 무조건 rvalue가 됨

       

2. forward

template <class _Ty>
constexpr _Ty&& forward(remove_reference_t<_Ty>& _Arg) noexcept {
    return static_cast<_Ty&&>(_Arg);
}

template <class _Ty>
constexpr _Ty&& forward(remove_reference_t<_Ty>&& _Arg) noexcept {
    static_assert(!is_lvalue_reference_v<_Ty>, "bad forward call");
    return static_cast<_Ty&&>(_Arg);
}

2-1. 인자값

forward(remove_reference_t<_Ty>& _Arg) noexcept

type에 존재하는 reference를 지워버리고 추가로 reference 연산으로 받는다 즉, _arg가 lvalue일 경우에 받는다

forward(remove_reference_t<_Ty>&& _Arg) noexcept

이 부분도 위와 같이 기존 존재하는 reference를 지우고 추가로 이동연산으로 받는다 즉, _arg가 rvalue일 경우에 받는다

   

이와 같이 lvalue와 rvalue를 나눠서 받는 이유는 다음 처리를 하기 위해서다

static_assert(!is_lvalue_reference_v<_Ty>, "bad forward call");

static_assert : 컴파일 타임 assert. 조건식이 false면 에러를 발생시킨다

is_lvalue_reference_v<type> : 들어온 type이 lvalue면 true를 반환해주는 type-trait

즉, 이 부분은 들어온 type이 lvalue라면 에러를 발생시키겠다는 의미이다.

그럼 여기서 궁금증이 생기는데

forward(remove_reference_t<_Ty>&& _Arg) noexcept {
    static_assert(!is_lvalue_reference_v<_Ty>, "bad forward call");

들어온 인자값이 rvalue인데 해당 타입이 lvalue일 경우가 있을까? 다음과 같은 경우가 있다.

std::forward<std::string&>(std::string{});

해당 예시를 보면 들어오는 값 자체는 rvalue(string{})로 들어오지만 타입은 lvalue(string&)로 들어왔기 때문에 에러를 발생시킨다

   

2-2. 함수내부

return static_cast<_Ty&&>(_Arg);

들어오는 타입을 _Ty&& 형태로 캐스팅 해주는데 이게 단순이 rvalue로서의 캐스팅이 아니다

   

Reference Collapsing

기존 타입의 Reference와 Reference casting이 합쳐지면 다음과 같이 작동한다 Image 일반 자료형의 경우 casting을 하면 &, && 로 무조건 casting된다

하지만 & 또는 && 를 만나게 되면 Reference Collapsing 법칙에 따라 동작한다 단순하게 생각하면 _Ty&&가 되는 경우는 &&와 &&가 만났을 때 뿐이고 &를 1, && 를 0이라고 한 뒤 두 개를 or 연산한다고 생각하면 편하다

따라서 이 부분은 결국

return static_cast<_Ty&&>(_Arg);

기존 타입(_Ty)이 rvalue면 rvalue로서의 casting을 수행하고 lvalue면 lvalue로서의 casting을 수행하기 때문에 기존에 알고 있던 forward의 기능이 잘 동작한다

2-3. 반환 타입

constexpr _Ty&&

반환 타입 역시 Universal Reference로 받고 있기 때문에 lvalue -> lvalue rvalue -> rvalue 로서 반환타입을 잘 표시한다

댓글남기기