PrevUpHomeNext

Class template recursive_wrapper

A recursive_wrapper<T> represents a heap-allocated instance of T.

Recursive wrapper is very useful, but you shouldn't normally create a recursive_wrapper yourself, instead that happens internally within a variant.

namespace strict_variant {

template <typename T>
class recursive_wrapper {
  T * m_t;

  void destroy() { delete m_t; }

public:
  ~recursive_wrapper() noexcept { this->destroy(); }

  template <typename... Args>
  recursive_wrapper(Args &&... args)
    : m_t(new T(std::forward<Args>(args)...)) {}

  recursive_wrapper(recursive_wrapper & rhs)
    : recursive_wrapper(static_cast<const recursive_wrapper &>(rhs)) {}

  recursive_wrapper(const recursive_wrapper & rhs)
    : m_t(new T(rhs.get())) {}

  // Pointer move
  recursive_wrapper(recursive_wrapper && rhs) noexcept //
    : m_t(rhs.m_t)                                     //
  {
    rhs.m_t = nullptr;
  }

  // Not assignable, we never actually need this, and it adds complexity
  // associated to lifetime of `m_t` object.
  recursive_wrapper & operator=(const recursive_wrapper &) = delete;
  recursive_wrapper & operator=(recursive_wrapper &&) = delete;

  T & get() & {
    STRICT_VARIANT_ASSERT(m_t, "Bad access!");
    return *m_t;
  }
  const T & get() const & {
    STRICT_VARIANT_ASSERT(m_t, "Bad access!");
    return *m_t;
  }
  T && get() && {
    STRICT_VARIANT_ASSERT(m_t, "Bad access!");
    return std::move(*m_t);
  }
};
[Caution] Caution

After a recursive_wrapper is moved from, UB occurs on attempt to dereference it, just like with std::unique_ptr.

This is different from boost::recursive_wrapper.

See Implementation Notes for a discussion of why it is this way and how variant handles this.


PrevUpHomeNext