aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/aloptional.h38
1 files changed, 32 insertions, 6 deletions
diff --git a/common/aloptional.h b/common/aloptional.h
index 895f5151..b76bebf1 100644
--- a/common/aloptional.h
+++ b/common/aloptional.h
@@ -17,6 +17,7 @@ constexpr in_place_t in_place{};
#define NOEXCEPT_AS(...) noexcept(noexcept(__VA_ARGS__))
+namespace detail_ {
/* Base storage struct for an optional. Defines a trivial destructor, for types
* that can be trivially destructed.
*/
@@ -102,14 +103,20 @@ struct optstore_helper : public optstore_base<T> {
};
/* Define copy and move constructors and assignment operators, which may or may
- * not be trivial. Default definition is completely trivial.
+ * not be trivial.
*/
template<typename T, bool trivial_copy = std::is_trivially_copy_constructible<T>::value,
bool trivial_move = std::is_trivially_move_constructible<T>::value,
- /* Trivial assignment is dependent on trivial construction. */
- bool = trivial_copy && std::is_trivially_copy_assignable<T>::value,
- bool = trivial_move && std::is_trivially_move_assignable<T>::value>
-struct optional_storage : public optstore_helper<T> {
+ /* Trivial assignment is dependent on trivial construction+destruction. */
+ bool = trivial_copy && std::is_trivially_copy_assignable<T>::value
+ && std::is_trivially_destructible<T>::value,
+ bool = trivial_move && std::is_trivially_move_assignable<T>::value
+ && std::is_trivially_destructible<T>::value>
+struct optional_storage;
+
+/* Completely trivial. */
+template<typename T>
+struct optional_storage<T, true, true, true, true> : public optstore_helper<T> {
using optstore_helper<T>::optstore_helper;
constexpr optional_storage() noexcept = default;
constexpr optional_storage(const optional_storage&) = default;
@@ -224,10 +231,13 @@ struct optional_storage<T, false, false, false, false> : public optstore_helper<
{ this->assign(std::move(rhs)); return *this; }
};
+} // namespace detail_
+
+#define REQUIRES(...) bool rt_=true, std::enable_if_t<rt_ && (__VA_ARGS__),bool> = true
template<typename T>
class optional {
- using storage_t = optional_storage<T>;
+ using storage_t = detail_::optional_storage<T>;
storage_t mStore{};
@@ -240,8 +250,23 @@ public:
constexpr optional(nullopt_t) noexcept { }
template<typename ...Args>
constexpr explicit optional(in_place_t, Args&& ...args)
+ NOEXCEPT_AS(storage_t{al::in_place, std::forward<Args>(args)...})
: mStore{al::in_place, std::forward<Args>(args)...}
{ }
+ template<typename U, REQUIRES(std::is_constructible<T, U&&>::value
+ && !std::is_same<std::decay_t<U>, al::in_place_t>::value
+ && !std::is_same<std::decay_t<U>, optional<T>>::value
+ && std::is_convertible<U&&, T>::value)>
+ constexpr optional(U&& rhs) NOEXCEPT_AS(storage_t{al::in_place, std::forward<U>(rhs)})
+ : mStore{al::in_place, std::forward<U>(rhs)}
+ { }
+ template<typename U, REQUIRES(std::is_constructible<T, U&&>::value
+ && !std::is_same<std::decay_t<U>, al::in_place_t>::value
+ && !std::is_same<std::decay_t<U>, optional<T>>::value
+ && !std::is_convertible<U&&, T>::value)>
+ constexpr explicit optional(U&& rhs) NOEXCEPT_AS(storage_t{al::in_place, std::forward<U>(rhs)})
+ : mStore{al::in_place, std::forward<U>(rhs)}
+ { }
~optional() = default;
constexpr optional& operator=(const optional&) = default;
@@ -298,6 +323,7 @@ template<typename T, typename U, typename... Args>
constexpr optional<T> make_optional(std::initializer_list<U> il, Args&& ...args)
{ return optional<T>{in_place, il, std::forward<Args>(args)...}; }
+#undef REQUIRES
#undef NOEXCEPT_AS
} // namespace al