# C++11中的完美转发

## 背景问题

我们想要创建创建一个工厂模版函数`factory`, 使用`Arg`类型的参数`arg`，构造一个T对象，并返回它的`shared_ptr`, 我们的理想是**`factory`就像不存在一样**，因此我们需要一个`完美转发`(perfect forwarding):

* 如果参数是 左值引用，直接以 左值引用 的形式，转发给下一个函数
* 如果参数是 右值引用，要先 “还原” 为 右值引用 的形式，再转发给下一个函数

## 解决方案

完美转发的两个特定，对应着两个要求
1. 必须按引用传递；且左值和右值必须都能引用
2. 若引用右值，必须保留右值的特征

对于第一点，`通用引用`可以完成。
对于第二点，通用引用后，无论是`左值引用`还是`右值引用`，他们都是`左值`，对于左值引用直接转发就可以，但是对于右值引用，我们需要使用`static_cast`将它转化为一个右值后转发。

## 函数定义
```cpp
template<typename T, typename Arg>
std::shared_ptr<T> factory(Arg&& arg) {
    return std::shared_ptr<T>(new T(forward<Arg>(arg)));
}

template<typename S>
S&& forward(typename std::remove_reference<S>::type& s) noexcept {
    return static_cast<S&&>(s);
}

```
假设我们有一个类`Foo`, 拥有一个构造函数`Foo(int n)`

### 传递左值
```
// 当int x = 10; factory<Foo>(x) 传递一个左值时
// Arg&& arg是通用引用， Arg被推导为 int&
std::shared_ptr<Foo> factory(int& arg) {
    return std::shared_ptr<Foo>(new Foo(forward<int&>(arg)));
}

// 对于 forward<int&>(arg)
// S被推导为int&
int& && forward(int& s) noexcept {
    return static_cast<int& &&>(s);
}

// 进行引用折叠
int& forward(int& s) noexcept {
    return static_cast<int&>(s)
}
```
可以看出：当左值`arg`引用的是左值时，传递给`new Foo()`的是被引用的左值(被引用的左值再经过`static_cast<Foo&>`得到的还是左值引用)。

### 传递右值
```cpp
// 当 factory<Foo>(10), 传递一个右值时
// Arg&& 是通用阴影， Arg被推导为 int
std::shared_ptr<Foo> factory(int&& arg) {
    return std::shared_ptr<Foo>(new Foo(forward<int>(arg)));
}

// 对于 forward<int>(arg)
// S被推导为 int
int&& forward(int& s) noexcept {
    return static_cast<int&&>(s);
}

```

可以看出：当左值`arg`引用的是右值时，传递给`new T()`的是被引用的右值(static_cast<X&&>把`arg`强制为右值，因为没有名字)。


![download.jpg](https://cdn.hashnode.com/res/hashnode/image/upload/v1658562901308/GeSpj-Wl1.jpg align="left")

## Ref
1. https://www.yuanguohuo.com/2018/05/25/cpp11-perfect-forward/

