# std::reference_wrapper

< cpp‎ | utility‎ | functional

定义于头文件 `<functional>` |  |
template< class T > class reference_wrapper; |  | (C++11 起)

`std::reference_wrapper` 是包装引用于可复制、可赋值对象的类模板。它常用作将引用存储入无法正常保有引用的标准容器（类似 std::vector ）的机制。

特别是， `std::reference_wrapper` 是围绕到类型 `T` 的对象引用或函数引用的可复制构造 (CopyConstructible) 且可复制赋值 (CopyAssignable) 的包装器。 `std::reference_wrapper` 的实例是对象（它们可被复制或存储于容器），但它们能隐式转换成 T& ，故能以之为以引用接收底层类型的函数的参数。

若存储的引用可调用 (Callable) ，则可以相同参数调用 `std::reference_wrapper` 。

辅助函数 std::ref 与 std::cref 常用于生成 `std::reference_wrapper` 对象。

`std::reference_wrapper` 亦用于按引用传递对象给 std::bind 或 std::thread 的构造函数。

保证 `std::reference_wrapper` 为可平凡复制 (TriviallyCopyable) 。 | (C++17 起)

`T` 可为不完整类型。 | (C++20 起)

### 成员类型

类型 | 定义
`type` | `T`
`result_type`(C++17 中弃用)(C++20 中移除) | 若 `T` 为函数则为 `T` 的返回类型。否则不定义。
`argument_type`(C++17 中弃用)(C++20 中移除) | 1) 若 `T` 为接受一个 `A1` 类型参数的函数或指向函数指针，则 `argument_type` 为 `A1` 。 2) 若 `T` 是不接收参数的指向类 `T0` 成员函数的指针，则 `argument_type` 为 `T0*` ，可能有 cv 限定 3) 若 `T` 是拥有成员类型 `T::argument_type` 的类类型，则 `argument_type` 为其别名
`first_argument_type`(C++17 中弃用)(C++20 中移除) | 1) 若 `T` 是接收二个 `A1` 与 `A2` 类型参数的函数或指向函数指针，则 `first_argument_type` 为 `A1` 。 2) 若 `T` 是接收一个参数的指向 `T0` 成员函数指针，则 `first_argument_type` 为 `T0*` ，可能有 cv 限定 3) 若 `T` 是拥有成员类型 `T::first_argument_type` 的类类型，则 `first_argument_type` 为其别名
`second_argument_type`(C++17 中弃用)(C++20 中移除) | 1) 若 `T` 是接收二个 `A1` 与 `A2` 类型参数的函数或指向函数指针，则 `second_argument_type` 为 `A2` 。 2) 若 `T` 是接收一个 `A1` 类型参数的指向 `T0` 成员函数指针，则 `second_argument_type` 为 `A1` ，可有 cv 限定 3) 若 `T` 是拥有成员类型 `T::second_argument_type` 的类类型，则 `second_argument_type` 为其别名

### 成员函数

(构造函数) | 存储引用于新的 std::reference_wrapper 对象 (公开成员函数)
operator= | 重绑定 std::reference_wrapper (公开成员函数)
get operator T& | 访问存储的引用 (公开成员函数)
operator() | 调用其所存储的函数 (公开成员函数)

### 推导指引(C++17 起)

### 可能的实现

    namespace detail {
    template <class T> T& FUN(T& t) noexcept { return t; }
    template <class T> void FUN(T&&) = delete;
    }

    template <class T>
    class reference_wrapper {
    public:
      // 类型
      using type = T;

      // 构造/复制/销毁
      template <class U, class = decltype(
        detail::FUN<T>(std::declval<U>()),
        std::enable_if_t<!std::is_same_v<reference_wrapper, std::remove_cvref_t<U>>>()
      )>
      constexpr reference_wrapper(U&& u) noexcept(noexcept(detail::FUN<T>(std::forward<U>(u))))
        : _ptr(std::addressof(detail::FUN<T>(std::forward<U>(u)))) {}
      reference_wrapper(const reference_wrapper&) noexcept = default;

      // 赋值
      reference_wrapper& operator=(const reference_wrapper& x) noexcept = default;

      // 访问
      constexpr operator T& () const noexcept { return *_ptr; }
      constexpr T& get() const noexcept { return *_ptr; }

      template< class... ArgTypes >
      constexpr std::invoke_result_t<T&, ArgTypes...>
        operator() ( ArgTypes&&... args ) const {
        return std::invoke(get(), std::forward<ArgTypes>(args)...);
      }

    private:
      T* _ptr;
    };

    // 推导指引
    template<class T>
    reference_wrapper(T&) -> reference_wrapper<T>;

### 示例

演示将 reference_wrapper 作为引用的容器使用，这令用多重下标访问同一容器可行

    #include <algorithm>
    #include <list>
    #include <vector>
    #include <iostream>
    #include <numeric>
    #include <random>
    #include <functional>

    int main()
    {
        std::list<int> l(10);
        std::iota(l.begin(), l.end(), -4);

        std::vector<std::reference_wrapper<int>> v(l.begin(), l.end());
        // 不能在 list 上用 shuffle （要求随机访问），但能在 vector 上使用它
        std::shuffle(v.begin(), v.end(), std::mt19937{std::random_device{}()});

        std::cout << "Contents of the list: ";
        for (int n : l) std::cout << n << ' '; std::cout << '\n';

        std::cout << "Contents of the list, as seen through a shuffled vector: ";
        for (int i : v) std::cout << i << ' '; std::cout << '\n';

        std::cout << "Doubling the values in the initial list...\n";
        for (int& i : l) {
            i *= 2;
        }

        std::cout << "Contents of the list, as seen through a shuffled vector: ";
        for (int i : v) std::cout << i << ' '; std::cout << '\n';
    }

可能的输出：

    Contents of the list: -4 -3 -2 -1 0 1 2 3 4 5
    Contents of the list, as seen through a shuffled vector: -1 2 -2 1 5 0 3 -3 -4 4
    Doubling the values in the initial list...
    Contents of the list, as seen through a shuffled vector: -2 4 -4 2 10 0 6 -6 -8 8

### 参阅

ref cref (C++11)(C++11) | 创建具有从其实参推导的类型的 std::reference_wrapper (函数模板)
bind (C++11) | 绑定一或多个实参到函数对象 (函数模板)