From 94e83f04e104d672ff7f6c370114c58e98fd251b Mon Sep 17 00:00:00 2001 From: Simon Brand Date: Sun, 1 Oct 2017 14:54:19 +0100 Subject: [PATCH] Compilation fixes --- optional.hpp | 283 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 219 insertions(+), 64 deletions(-) diff --git a/optional.hpp b/optional.hpp index ed7f8d1..8b43bd2 100644 --- a/optional.hpp +++ b/optional.hpp @@ -11,24 +11,97 @@ /// #include -#include "tl/type_traits.hpp" +#include +#include +#include namespace tl { + template using remove_cv_t = typename std::remove_cv::type; + template using remove_const_t = typename std::remove_const::type; + template using remove_volatile_t = typename std::remove_volatile::type; + template using add_cv_t = typename std::add_cv::type; + template using add_const_t = typename std::add_const::type; + template using add_volatile_t = typename std::add_volatile::type; + template using remove_reference_t = typename std::remove_reference::type; + template using add_lvalue_reference_t = typename std::add_lvalue_reference::type; + template using add_rvalue_reference_t = typename std::add_rvalue_reference::type; + template using remove_pointer_t = typename std::remove_pointer::type; + template using add_pointer_t = typename std::add_pointer::type; + template using make_signed_t = typename std::make_signed::type; + template using make_unsigned_t = typename std::make_unsigned::type; + template using remove_extent_t = typename std::remove_extent::type; + template using remove_all_extents_t = typename std::remove_all_extents::type; + template using aligned_storage_t = typename std::aligned_storage::type; + template using aligned_union_t = typename std::aligned_union::type; + template using decay_t = typename std::decay::type; + template using enable_if_t = typename std::enable_if::type; + template using conditional_t = typename std::conditional::type; + template using common_type_t = typename std::common_type::type; + template using underlying_type_t = typename std::underlying_type::type; + template using result_of_t = typename std::result_of::type; + + template struct voider { using type = void; }; + template using void_t = typename voider::type; + + struct in_place_t { + explicit in_place_t() = default; + }; + static constexpr in_place_t in_place{}; + // [optional.optional], class template optional template class optional; + namespace detail { + template + using enable_forward_value = tl::enable_if_t< + std::is_constructible::value && + !std::is_same, in_place_t>::value && + !std::is_same, tl::decay_t>::value + >; + + template + using enable_from_other = tl::enable_if_t< + std::is_constructible::value && + !std::is_constructible&>::value && + !std::is_constructible&&>::value && + !std::is_constructible&>::value && + !std::is_constructible&&>::value && + !std::is_convertible&, T>::value && + !std::is_convertible&&, T>::value && + !std::is_convertible&, T>::value && + !std::is_convertible&&, T>::value + >; + } + + //TODO improve + template + struct is_swappable : std::false_type{}; + + template + struct is_swappable(), std::declval()))>> + : std::true_type{}; + + //TODO improve + template + struct is_nothrow_swappable : std::false_type{}; + + template + struct is_nothrow_swappable(), std::declval()))>> + : std::true_type{}; + // [optional.nullopt], no-value state indicator struct nullopt_t{ struct do_not_use{}; - constexpr explicit nullopt(do_not_use, do_not_use) noexcept{} + constexpr explicit nullopt_t(do_not_use, do_not_use) noexcept{} }; - inline constexpr nullopt_t nullopt{nullopt_t::do_not_use{}, nullopt_t::do_not_use{}}; + static constexpr nullopt_t nullopt{nullopt_t::do_not_use{}, nullopt_t::do_not_use{}}; - // [optional.bad.access], class bad_­optional_­access + // [optional.bad.access], class bad_optional_access class bad_optional_access : public std::exception { + public: bad_optional_access() = default; - const char* what() const { + const char* what() const noexcept { return "Optional has no value"; } }; @@ -79,7 +152,6 @@ namespace tl { return lhs.value() <= rhs.value(); } - } template inline constexpr bool operator>=(const optional& lhs, const optional& rhs) { if (!rhs.has_value()) @@ -168,30 +240,31 @@ template inline constexpr bool operator>=(const U& lhs, const // [optional.specalg], specialized algorithms -template ::value* = nullptr, - tl:enable_if_t>* = nullptr> +template ::value>* = nullptr, + tl::enable_if_t::value>* = nullptr> void swap(optional& lhs, optional& rhs) noexcept(noexcept(lhs.swap(rhs))) { return lhs.swap(rhs); } template inline constexpr optional> make_optional(T&& v) { - return optional>(std​::​forward(v)); + return optional>(std::forward(v)); } template inline constexpr optional make_optional(Args&&... args) { - return optional(in_place, std​::​forward(args)...); + return optional(in_place, std::forward(args)...); } template - inline constexpr optional make_optional(initializer_list il, Args&&... args) { - return optional(in_place, il, std​::​forward(args)...); + inline constexpr optional make_optional(std::initializer_list il, Args&&... args) { + return optional(in_place, il, std::forward(args)...); } } // [optional.hash], hash support namespace std { template struct hash; - template >{})> + //TODO SFINAE + template struct hash> { std::size_t operator() (const tl::optional& o) { if (!o.has_value()) @@ -199,143 +272,225 @@ namespace std { return hash>()(o.value()); } - } + }; } namespace tl { namespace detail { - template - struct optional_base : { + template ::value> + struct optional_storage_base { + ~optional_storage_base() { + if (m_has_value) { + m_value.~T(); + m_has_value = false; + } + } + struct dummy{}; + union { + dummy m_dummy; + T m_value; + }; + + bool m_has_value = false; + }; + + template + struct optional_storage_base { + ~optional_storage_base() { + if (m_has_value) { + //don't destruct value + m_has_value = false; + } + } + + struct dummy{}; + union { + dummy m_dummy; + T m_value; + }; + + bool m_has_value = false; }; } template -class optional : private detail::optional_base { +class optional : private detail::optional_storage_base { public: using value_type = T; // [optional.ctor], constructors constexpr optional() noexcept = default; - constexpr optional(nullopt_t) noexcept = default; - constexpr optional(const optional& rhs) = default; - constexpr optional(optional&&); - template - constexpr explicit optional(in_place_t, Args&&...); - template - constexpr explicit optional(in_place_t, initializer_list, Args&&...); - template - EXPLICIT constexpr optional(U&&); - template - EXPLICIT optional(const optional&); - template - EXPLICIT optional(optional&&); + constexpr optional(nullopt_t) noexcept {}; + constexpr optional(const optional& rhs) { + if (rhs.has_value()) { + this->m_has_value = true; + new (std::addressof(this->m_value)) T (rhs.value()); + } + } + template ::value>* = nullptr> + constexpr optional(optional&& rhs) { + if (rhs.has_value()) { + this->m_has_value = true; + new (std::addressof(this->m_value)) T (std::move(rhs.value())); + } + } + template + constexpr explicit optional(tl::enable_if_t::value, in_place_t>, + Args&&... args) { + this->m_has_value = true; + new (std::addressof(this->m_value)) T (std::forward(args)...); + } + template + constexpr explicit optional( + tl::enable_if_t&, Args&&...>::value, in_place_t>, + std::initializer_list il, Args&&... args) { + this->m_has_value = true; + new (std::addressof(this->m_value)) T (il, std::forward(args)...); + } + + template ::value>* = nullptr, + detail::enable_forward_value* = nullptr> + constexpr optional(U&& u) { + this->m_has_value = true; + new (std::addressof(this->m_value)) T (std::forward(u)); + } + + template ::value>* = nullptr, + detail::enable_forward_value* = nullptr> + constexpr explicit optional(U&& u) { + this->m_has_value = true; + new (std::addressof(this->m_value)) T (std::forward(u)); + } + + template * = nullptr, + tl::enable_if_t::value>* = nullptr> + optional(const optional& rhs) { + this->m_has_value = true; + new (std::addressof(this->m_value)) T (rhs.value()); + } + + template * = nullptr, + tl::enable_if_t::value>* = nullptr> + optional(const optional& rhs) { + this->m_has_value = true; + new (std::addressof(this->m_value)) T (rhs.value()); + } + + template * = nullptr, + tl::enable_if_t::value>* = nullptr> + optional(optional&& rhs) { + this->m_has_value = true; + new (std::addressof(this->m_value)) T (std::move(rhs.value())); + } + + + template * = nullptr, + enable_if_t::value>* = nullptr> + explicit optional(optional&& rhs) { + this->m_has_value = true; + new (std::addressof(this->m_value)) T (std::move(rhs.value())); + } // [optional.dtor], destructor - ~optional(); + ~optional() = default; // [optional.assign], assignment optional& operator=(nullopt_t) noexcept; optional& operator=(const optional&); - optional& operator=(optional&&) noexcept(see below); + optional& operator=(optional&&) noexcept; template optional& operator=(U&&); template optional& operator=(const optional&); template optional& operator=(optional&&); - template T& emplace(Args&&...) { + template T& emplace(Args&&... args) { static_assert(std::is_constructible::value, "T must be constructible with Args"); *this = nullopt; - new (std::addressof(m_storage.t)) T(std​::​forward(args)...); + new (std::addressof(this->m_value)) T(std::forward(args)...); } template tl::enable_if_t&, Args&&...>::value, T&> - T& emplace(initializer_list, Args&&...) { + emplace(std::initializer_list il, Args&&... args) { *this = nullopt; - new (std::addressof(m_storage.t)) T(il, std​::​forward(args)...); + new (std::addressof(this->m_value)) T(il, std::forward(args)...); } // [optional.swap], swap void swap(optional& rhs) - noexcept(std::is_nothrow_move_constructible_v::value && std::is_nothrow_swappable::value) + noexcept(std::is_nothrow_move_constructible::value && is_nothrow_swappable::value) { - if (lhs.has_value()) { + if (has_value()) { if (rhs.has_value()) { using std::swap; swap(value(), rhs.value()); } else { - new (&rhs.m_storage.t) T (std::move(m_storage.t)); - m_storage.t.T::~T(); + new (&rhs.m_value) T (std::move(this->m_value)); + this->m_value.T::~T(); } } else if (rhs.has_value()) { - new (std::addressof(m_storage.t)) T (std::move(rhs.m_storage.t)); - rhs.m_storage.t.T::~T(); + new (std::addressof(this->m_value)) T (std::move(rhs.m_value)); + rhs.m_value.T::~T(); } } // [optional.observe], observers constexpr const T* operator->() const { - return std::addressof(m_storage.t); + return std::addressof(this->m_value); } constexpr T* operator->() { - return std::addressof(m_storage.t); + return std::addressof(this->m_value); } constexpr const T& operator*() const& { - return m_storage.t; + return this->m_value; } constexpr T& operator*() & { - return m_storage.t; + return this->m_value; } constexpr T&& operator*() && { - return std::move(m_storage.t); + return std::move(this->m_value); } constexpr const T&& operator*() const&& { - return std::move(m_storage.t); + return std::move(this->m_value); } constexpr explicit operator bool() const noexcept { - return m_has_value; + return this->m_has_value; } constexpr bool has_value() const noexcept { - return m_has_value; + return this->m_has_value; } constexpr const T& value() const& { - return has_value() ? m_storage.t : throw bad_optional_access(); + return has_value() ? this->m_value : throw bad_optional_access(); } constexpr T& value() & { - return has_value() ? m_storage.t : throw bad_optional_access(); + return has_value() ? this->m_value : throw bad_optional_access(); } constexpr T&& value() && { - return has_value() ? std::move(m_storage.t) : throw bad_optional_access(); + return has_value() ? std::move(this->m_value) : throw bad_optional_access(); } constexpr const T&& value() const&& { - return has_value() ? std::move(m_storage.t) : throw bad_optional_access(); + return has_value() ? std::move(this->m_value) : throw bad_optional_access(); } - template constexpr T value_or(U&&) const& { + template constexpr T value_or(U&& u) const& { static_assert(std::is_copy_constructible::value && std::is_convertible::value, "T must be copy constructible and convertible from U"); - return has_value() ? value() : static_cast(std::forward(v)); + return has_value() ? value() : static_cast(std::forward(u)); } - template constexpr T value_or(U&&) && { + template constexpr T value_or(U&& u) && { static_assert(std::is_move_constructible::value && std::is_convertible::value, "T must be move constructible and convertible from U"); - return has_value() ? value() : static_cast(std::forward(v)); + return has_value() ? value() : static_cast(std::forward(u)); } // [optional.mod], modifiers void reset() noexcept; private: - struct dummy{}; - union { - dummy d; - T t; - } m_storage; - bool m_has_value; }; }