----------------
title : C++ 레퍼런스 - std::forward 함수
cat_title :  forward
ref_title : forward, std::forward
path : /C++ Reference/utility
publish_date : 2019-09-28
----------------

##@ cpp-ref-start

#@ std::forward

`<utility>` 에 정의됨

```cpp-formatted
// 참고로 C++ 14 이전 버전에는 constexpr 이 아니다.
template <class T>
constexpr T&& forward(std::remove_reference_t<T>& t) noexcept;  // (1)

template <class T>
constexpr T&& forward(std::remove_reference_t<T>&& t) noexcept;  // (2)
```

1 번 오버로딩의 경우 \serif{lvalue} 를 `T` 에 따라 \serif{lvalue} 혹은 \serif{rvalue} 로 전달한다.

만일 `t` 가 **보편적 레퍼런스(Universal reference)** 라면, (1) 번 오버로딩 함수의 경우 `t` 를 다른 함수에 값 카테고리를 그대로 유지한채 전달하게 된다. 참고로 보편적 레퍼런스는, 템플릿 인자 T 를 인자로 받는 우측값 레퍼런스로 예를 들어서;

```cpp-formatted
template <class T>
void wrapper(T&& arg) {
  // arg is always lvalue
  foo(std::forward<T>(arg));  // Forward as lvalue or as rvalue, depending on T
}
```

위 경우 `arg` 가 보편적 레퍼런스 이다. (템플릿 인자 `T` 의 우측값 레퍼런스 이므로). 이 때 `arg` 자체는 \serif{lvalue} 이므로 1 번 `std::forward` 가 오버로딩 된다.

* 만일 `wrapper()` 에 \serif{rvalue} `std::string` 을 전달한다면, `T` 는 `std::string` 으로 추론된다 (`std::string&, const std::string&, std::string&&` 이 아님!) 그리고 `std::forward` 가 `foo` 에 우측값 레퍼런스를 전달하게 된다.
* 만일 `wrapper()` 에 상수 \serif{lvalue} `std::string` 을 전달한다면, `T` 는 `const std::string&` 으로 추론되며, `std::forward` 가 `foo` 에 상수 좌측값 레퍼런스를 전달한다.
* 만일 `wrapper()` 에 상수가 아닌 \serif{lvalue} `std::string` 을 전달한다면 `T` 는 `std::string&` 으로 추론되고, `std::forward` 는 상수가 아닌 좌측값 레퍼런스를 `foo` 에 전달한다.

2 번 오버로딩의 경우 \serif{rvalue} 는 \serif{rvalue} 로 전달하고, \serif{rvalue} 가 \serif{lvalue} 로 전달되는 것을 막는다.

사실 두 번째 오버로딩의 경우 필요한 이유가 조금 복잡하다. 예를 들어서 아래와 같은 상황을 생각해보자.

```cpp-formatted
std::forward<T>(u.get());
```

만일 사용자가 `u.get()` 이 \serif{lvalue} 를 리턴할지, \serif{rvalue} 를 리턴할지 모른다고 해보자. 하지만 `T` 가 좌측값 레퍼런스 타입이 아니라면, `u.get()` 이 리턴한 것을 이동 시키고 싶을 것이다. 반면에 `T` 가 좌측값 레퍼런스 타입이라면 `u.get()` 이 리턴한 것을 이동하면 **안된다**

사실 두 번째 형태의 `forward` 오버로딩을 사용할 경우는 거의 없을 테므로 굳이 걱정할 필요는 없다. 두 번째 형태의 `forward` 가 왜 필요한지 자세한 설명은 [표준 문서](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2951.html)를 읽어보는 것을 권장한다.

### 인자들

* t	: 전달할 객체

### 리턴값

`static_cast<T&&>(t)`

### 실헹 예제

```cpp-formatted
#include <iostream>
#include <memory>
#include <utility>

struct A {
  A(int&& n) { std::cout << "rvalue overload, n=" << n << "\n"; }
  A(int& n) { std::cout << "lvalue overload, n=" << n << "\n"; }
};

class B {
 public:
  template <class T1, class T2, class T3>
  B(T1&& t1, T2&& t2, T3&& t3)
      : a1_{std::forward<T1>(t1)},
        a2_{std::forward<T2>(t2)},
        a3_{std::forward<T3>(t3)} {}

 private:
  A a1_, a2_, a3_;
};

template <class T, class U>
std::unique_ptr<T> make_unique1(U&& u) {
  return std::unique_ptr<T>(new T(std::forward<U>(u)));
}

template <class T, class... U>
std::unique_ptr<T> make_unique2(U&&... u) {
  return std::unique_ptr<T>(new T(std::forward<U>(u)...));
}

int main() {
  auto p1 = make_unique1<A>(2);  // rvalue
  int i = 1;
  auto p2 = make_unique1<A>(i);  // lvalue

  std::cout << "B\n";
  auto t = make_unique2<B>(2, i, 3);
}
```

```exec
rvalue overload, n=2
lvalue overload, n=1
B
rvalue overload, n=2
lvalue overload, n=1
rvalue overload, n=3
```

### 참고 자료

* `move` : 객체의 우측값 레퍼런스를 얻는다.
* `move_if_noexcept` : 생성자가 예외를 던지지 않을 경우에만 우측값 레퍼런스를 얻는다.