
[#virtual_ptr]
:idprefix: virtual_ptr_

## virtual_ptr

### Synopsis

`virtual_ptr` is defined in `<boost/openmethod/core.hpp>`.

```c++
namespace boost::openmethod {

template<class Class, class Policy = BOOST_OPENMETHOD_DEFAULT_POLICY>
class virtual_ptr {
  public:
    static constexpr bool is_smart_ptr = /* see below */;
    using element_type = /* see below */;

    template<class Other> virtual_ptr(Other& other);
    template<class Other> virtual_ptr(const Other& other);
    template<class Other> virtual_ptr(Other&& other);

    template<class Other>
    static auto final(Other&& obj);

    auto get() const -> element_type*;
    auto operator->() const -> element_type*;
    auto operator*() const -> element_type&;
    auto pointer() const -> const Class*&;

    template<typename Other>
    auto cast() const -> virtual_ptr<Other, Policy>;
};

template<class Class>
virtual_ptr(Class&) -> virtual_ptr<Class, BOOST_OPENMETHOD_DEFAULT_POLICY>;

template<class Class>
inline auto final_virtual_ptr(Class& obj) -> virtual_ptr<
    Class, BOOST_OPENMETHOD_DEFAULT_POLICY>;

template<class Policy, class Class>
inline auto final_virtual_ptr(Class& obj) -> virtual_ptr<Class, Policy>;

template<class Left, class Right, class Policy>
bool operator==(
    const virtual_ptr<Left, Policy>& left,
    const virtual_ptr<Right, Policy>& right);

template<class Left, class Right, class Policy>
bool operator!=(
    const virtual_ptr<Left, Policy>& left,
    const virtual_ptr<Right, Policy>& right);

} // namespace boost::openmethod
```

Defined in `<boost/openmethod/shared_ptr.hpp>`:

```c++
namespace boost::openmethod {

template<class Class, class Policy = BOOST_OPENMETHOD_DEFAULT_POLICY>
using shared_virtual_ptr = virtual_ptr<std::shared_ptr<Class>, Policy>;

template<
    class Class, class Policy = BOOST_OPENMETHOD_DEFAULT_POLICY, typename... T>
inline auto make_shared_virtual(T&&... args);

}
```
Defined in `<boost/openmethod/unique_ptr.hpp>`:

```c++
namespace boost::openmethod {

template<class Class, class Policy = BOOST_OPENMETHOD_DEFAULT_POLICY>
using unique_virtual_ptr = virtual_ptr<std::unique_ptr<Class>, Policy>;

template<
    class Class, class Policy = BOOST_OPENMETHOD_DEFAULT_POLICY, typename... T>
inline auto make_unique_virtual(T&&... args);

}
```

### Description

`virtual_ptr` is a wide pointer that combines a pointer to an object and a
pointer to its v-table. The object pointer can be a plain pointer or a smart
pointer. Specializations of `virtual_traits` are required for smart pointers.
They are provided for `std::unique_ptr` and `std::shared_ptr`.

A plain `virtual_ptr` can be constructed from a reference, a smart pointer, or
another `virtual_ptr`. A smart `virtual_ptr` can be constructed from a smart
pointer or from a smart `virtual_ptr`. Usual conversions - from derived to base,
and from non-const to const - are allowed.

`virtual_ptr` does not have a default constructor, nor a "null" state. In that
respect, it behaves more like a reference than a pointer. The only reason why it
is not called `virtual_ref` is to save the name for the day C++ will support
smart references.

### Members

#### is_smart_ptr

```c++
static constexpr bool is_smart_ptr;
```

`true` if `Class` is a smart pointer, `false` otherwise. The value is derived
from `virtual_traits<Class, Policy>`: if it has a member template called
`rebind`, `Class` is considered a smart pointer.

#### element_type

```c++
using element_type = std::conditional_t<
    is_smart_ptr, typename Class::element_type, Class>;
```

The class of the object pointed to.

#### constructors

[source,c++]
----
template<class Other> virtual_ptr(Other& other);        // 1
template<class Other> virtual_ptr(const Other& other);  // 2
template<class Other> virtual_ptr(Other&& other);       // 3
----

(1), (2) If `virtual_ptr` uses a plain pointer, `other` must be a lvalue
reference to an object of a registered class, or to a `virtual_ptr` (plain or
smart). If `virtual_ptr` uses a smart pointer, `other` must be a reference to a smart
pointer, or a smart `virtual_ptr`.

(3) Smart `virtual_ptr` only. Constructs a `virtual_ptr` from a smart pointer or
a smart `virtual_ptr`. The (smart) object pointer is moved from `other`.

If `other` is also a `virtual_ptr`, the v-table pointer is copied from it.
Otherwise, it is deduced from the object. The `Policy` must be the same for both
`virtual_ptr`{empty}s.


#### final

```c++
template<class Other>
static auto final(Other&& obj);
```

Constructs a `virtual_ptr` from a reference to an object, or from a smart
pointer. It is assumed that the static and dynamic types are the same. The
v-table pointer is initialized from the `Policy::static_vptr` for the class,
which needs not be polymorphic.

#### get

```c++
auto get() const -> element_type*;
```

Returns a pointer to the object.

#### operator->

```c++
auto operator->() const -> element_type*;
```

Returns a pointer to the object.

#### operator*

```c++
auto operator*() const -> element_type&;
```

Returns a reference to the object.

#### pointer

```c++
auto pointer() const;
```

Returns a reference to the object pointer, which can be either a plain pointer
or a smart pointer.

#### cast

```c++
template<typename Other>
auto cast() const -> virtual_ptr<Other, Policy>;
```

Returns a `virtual_ptr` to the same object, cast to `Other`.

### Deduction guide

```c++
template<class Class>
virtual_ptr(Class&) -> virtual_ptr<Class, BOOST_OPENMETHOD_DEFAULT_POLICY>;
```

---

### Non-members

#### virtual_shared_ptr

```c++
template<class Class, class Policy = BOOST_OPENMETHOD_DEFAULT_POLICY>
using virtual_shared_ptr = virtual_ptr<std::shared_ptr<Class>, Policy>;
```

Convenience alias for `virtual_ptr<std::shared_ptr<Class>, Policy>`.

#### virtual_unique_ptr

```c++
template<class Class, class Policy = BOOST_OPENMETHOD_DEFAULT_POLICY>
using virtual_unique_ptr = virtual_ptr<std::unique_ptr<Class>, Policy>;
```

Convenience alias for `virtual_ptr<std::unique_ptr<Class>, Policy>`.

#### final_virtual_ptr

```c++
template<class Policy, class Class>
inline auto final_virtual_ptr(Class&& obj);

template<class Class>
inline auto final_virtual_ptr(Class&& obj);
```

Utility functions, forwarding to `virtual_ptr<Class, Policy>::final`.

If `Policy` is not specified, `BOOST_OPENMETHOD_DEFAULT_POLICY` is used.

#### make_virtual_shared

```c++
template<
    class Class, class Policy = BOOST_OPENMETHOD_DEFAULT_POLICY, typename... T>
inline auto make_virtual_shared(T&&... args);
```

Creates an object using `std::make_shared` and returns a `virtual_shared_ptr` to
it. The v-table pointer is initialized from the the `Policy::static_vptr` for
the class, which needs not be polymorphic.

#### make_virtual_unique

```c++
template<
    class Class, class Policy = BOOST_OPENMETHOD_DEFAULT_POLICY, typename... T>
inline auto make_virtual_unique(T&&... args);
```

Creates an object using `std::make_unique` and returns a `virtual_unique_ptr` to
it. The v-table pointer is initialized from the the `Policy::static_vptr` for
the class, which needs not be polymorphic.

#### operator==

```c++
template<class Left, class Right, class Policy>
bool operator==(
    const virtual_ptr<Left, Policy>& left,
    const virtual_ptr<Right, Policy>& right);
```

Compares two `virtual_ptr` objects for equality.

#### operator!=

```c++
template<class Left, class Right, class Policy>
bool operator!=(
    const virtual_ptr<Left, Policy>& left,
    const virtual_ptr<Right, Policy>& right);
```

Compares two `virtual_ptr` objects for inequality.
