# std::to_address

< cpp‎ | memory

定义于头文件 `<memory>` |  |
template< class Ptr > constexpr auto to_address(const Ptr& p) noexcept; | (1) | (C++20 起)
template< class T > constexpr T* to_address(T* p) noexcept; | (2) | (C++20 起)

获得 `p` 所指向的地址，而不形成到被指向者的引用：

1) 缀饰指针重载：若表达式 std::pointer_traits<Ptr>::to_address(p) 为良构，则返回该表达式的结果。否则，返回 std::to_address(p.operator->()) 。
2) 裸指针重载：若 `T` 为函数类型，则程序为谬构，否则返回不修改的 p 。

### 参数

p | - | 缀饰或裸指针

### 返回值

表示与 `p` 所表示者相同地址的裸指针。

### 可能的实现

    template<class T>
    constexpr T* to_address(T* p) noexcept
    {
        static_assert(!std::is_function_v<T>);
        return p;
    }

    template<class T>
    constexpr auto to_address(const T& p) noexcept
    {
        if constexpr (requires{ std::pointer_traits<T>::to_address(p); }) {
            return std::pointer_traits<T>::to_address(p);
        } else {
            return std::to_address(p.operator->());
        }
    }

### 注解

即使在 `p` 引用的存储中无已构造的对象时，也能使用 `std::to_address` ，该情况下不能用 std::addressof(*p) ，因为无可绑定 std::addressof 参数的合法对象。

`to_address` 的缀饰指针重载审查 std::pointer_traits<Ptr> 特化。若实例化该特化自身为谬构（往往是因为无法定义 `element_type` ），则导致立即语境外的硬错误并使得程序为谬构。

### 示例

    #include <memory>

    template<class A>
    auto allocator_new(A& a)
    {
        auto p = a.allocate(1);
        try {
            std::allocator_traits<A>::construct(a, std::to_address(p));
        } catch (...) {
            a.deallocate(p, 1);
            throw;
        }
        return p;
    }

    template<class A>
    void allocator_delete(A& a, typename std::allocator_traits<A>::pointer p)
    {
        std::allocator_traits<A>::destroy(a, std::to_address(p));
        a.deallocate(p, 1);
    }

    int main()
    {
        std::allocator<int> a;
        auto p = allocator_new(a);
        allocator_delete(a, p);
    }

### 参阅

pointer_traits (C++11) | 提供关于指针式类型的信息 (类模板)
to_address [静态] (C++20)(可选) | 从缀饰指针获得裸指针（ `pointer_to` 的反函数） (`std::pointer_traits<Ptr>` 的公开静态成员函数)