# std::pointer_traits

< cpp‎ | memory

定义于头文件 `<memory>` |  |
template< class Ptr > struct pointer_traits; | (1) | (C++11 起)
template< class T > struct pointer_traits<T*>; | (2) | (C++11 起)

`pointer_traits` 类模板提供标准化方法，访问类指针类型（缀饰指针，如 `boost::interprocess::offset_ptr` ）的某些属性。标准模板 std::allocator_traits 依靠 `pointer_traits` 确定多种分配器 (Allocator) 所要求的 typedef 的默认行为。

1) 非特化 `pointer_traits` 声明下列类型：

### 成员类型

类型 | 定义
`pointer` | Ptr
`element_type` | 若存在则为 Ptr::element_type 。否则若 `Ptr` 是模板特化 Template<T, Args...> 则为 `T` 。否则该 `pointer_traits` 特化为谬构
`difference_type` | 若存在则为 Ptr::difference_type ，否则为 std::ptrdiff_t

### 成员别名模板

模板 | 定义
template <class U> using rebind | 若存在则为 Ptr::rebind<U> ，否则若 `Ptr` 是模板特化 Template<T, Args...> 则为 Template<U, Args...>

### 成员函数

pointer_to [静态] | 获得指向其参数的可解引用指针 (公开静态成员函数)
##### 程序定义特化的可选成员函数
to_address [静态] (C++20)(可选) | 从缀饰指针获得裸指针（ `pointer_to` 的反函数） (公开静态成员函数)

2) 为指针类型 `T*` 提供的特化，它声明下列类型：

### 成员类型

类型 | 定义
`pointer` | T*
`element_type` | T
`difference_type` | std::ptrdiff_t

### 成员别名模版

模板 | 定义
template <class U> using rebind | U*

### 成员函数

pointer_to [静态] | 获得指向其参数的可解引用指针 (公开静态成员函数)

### 注解

重绑定成员模板别名，使得可以由指向 `T` 的类指针类型，获取指向 `U` 的相同类指针类型。例如，

    typedef std::pointer_traits<std::shared_ptr<int>>::rebind<double> another_pointer;
    static_assert(std::is_same<another_pointer, std::shared_ptr<double>>::value);

对用户定义指针类型的特化可提供额外的静态成员函数 `to_address` 以定制 std::to_address 的行为。 | (C++20 起)

### 示例

    #include <memory>
    #include <iostream>

    template <class Ptr>
    struct BlockList
    {
       // 预定义内存块
       struct block;

       // 从指针类别 Ptr 定义指向内存块的指针
       // 若 Ptr 是任何 T* 类型，则 block_ptr_t 为 block*
       // 若 Ptr 是 smart_ptr<T> ，则 block_ptr_t 为 smart_ptr<block>
       using block_ptr_t = typename std::pointer_traits<Ptr>::template rebind<block>;

       struct block
       {
          std::size_t size{};
          block_ptr_t next_block{};
       };

       block_ptr_t free_blocks;
    };

    int main()
    {
        [[maybe_unused]] BlockList<int*> bl1;
        // bl1.free_blocks 的类型是 BlockList<int*>::block*

        BlockList<std::shared_ptr<char>> bl2;
        // bl2.free_blocks 的类型是 std::shared_ptr< BlockList<std::shared_ptr<char> >::block>
        std::cout << bl2.free_blocks.use_count() << '\n';
    }

输出：

    ​0​

### 参阅

allocator_traits (C++11) | 提供关于分配器类型的信息 (类模板)
addressof (C++11) | 获得对象的实际地址，即使其重载了 & 运算符 (函数模板)