Commit c6d63bb7 authored by Dominik Charousset's avatar Dominik Charousset

Implement noexcept-correctness for variant

parent 608879a9
...@@ -118,10 +118,34 @@ using variant_visit_result_t = ...@@ -118,10 +118,34 @@ using variant_visit_result_t =
template <class... Ts> template <class... Ts>
class variant { class variant {
public: public:
// -- member types -----------------------------------------------------------
using types = detail::type_list<Ts...>; using types = detail::type_list<Ts...>;
using type0 = typename detail::tl_at<types, 0>::type;
// -- constants --------------------------------------------------------------
/// Stores the ID for the last type.
static constexpr int max_type_id = sizeof...(Ts) - 1; static constexpr int max_type_id = sizeof...(Ts) - 1;
/// Stores whether all types are nothrow constructible.
static constexpr bool nothrow_move_construct =
detail::conjunction<
std::is_nothrow_move_constructible<Ts>::value...
>::value;
/// Stores whether all types are nothrow assignable *and* constructible. We
/// need to check both, since assigning to a variant results in a
/// move-contruct unless the before and after types are the same.
static constexpr bool nothrow_move_assign =
nothrow_move_construct
&& detail::conjunction<
std::is_nothrow_move_assignable<Ts>::value...
>::value;
// -- sanity checks ----------------------------------------------------------
static_assert(sizeof...(Ts) <= 20, "Too many template arguments given."); static_assert(sizeof...(Ts) <= 20, "Too many template arguments given.");
static_assert(sizeof...(Ts) > 0, "No template argument given."); static_assert(sizeof...(Ts) > 0, "No template argument given.");
...@@ -129,19 +153,7 @@ public: ...@@ -129,19 +153,7 @@ public:
static_assert(!detail::tl_exists<types, std::is_reference>::value, static_assert(!detail::tl_exists<types, std::is_reference>::value,
"Cannot create a variant of references"); "Cannot create a variant of references");
using type0 = typename detail::tl_at<types, 0>::type; // -- constructors, destructors, and assignment operators --------------------
variant& operator=(const variant& other) {
variant_assign_helper<variant> helper{*this};
other.template apply<void>(helper);
return *this;
}
variant& operator=(variant&& other) {
variant_move_helper<variant> helper{*this};
other.template apply<void>(helper);
return *this;
}
variant() : type_(variant_npos) { variant() : type_(variant_npos) {
// Never empty ... // Never empty ...
...@@ -151,14 +163,16 @@ public: ...@@ -151,14 +163,16 @@ public:
} }
template <class U> template <class U>
variant(U&& arg) : type_(variant_npos) { variant(U&& arg)
noexcept(std::is_rvalue_reference<U&&>::value && nothrow_move_assign)
: type_(variant_npos) {
set(std::forward<U>(arg)); set(std::forward<U>(arg));
} }
template <class U> variant(variant&& other) noexcept(nothrow_move_construct)
variant& operator=(U&& arg) { : type_(variant_npos) {
set(std::forward<U>(arg)); variant_move_helper<variant> helper{*this};
return *this; other.template apply<void>(helper);
} }
variant(const variant& other) : type_(variant_npos) { variant(const variant& other) : type_(variant_npos) {
...@@ -166,15 +180,30 @@ public: ...@@ -166,15 +180,30 @@ public:
other.template apply<void>(helper); other.template apply<void>(helper);
} }
variant(variant&& other) : type_(variant_npos) { variant& operator=(const variant& other) {
variant_assign_helper<variant> helper{*this};
other.template apply<void>(helper);
return *this;
}
variant& operator=(variant&& other) noexcept(nothrow_move_assign) {
variant_move_helper<variant> helper{*this}; variant_move_helper<variant> helper{*this};
other.template apply<void>(helper); other.template apply<void>(helper);
return *this;
}
template <class U>
variant& operator=(U&& arg) noexcept(nothrow_move_assign) {
set(std::forward<U>(arg));
return *this;
} }
~variant() { ~variant() {
destroy_data(); destroy_data();
} }
// -- properties -------------------------------------------------------------
constexpr size_t index() const { constexpr size_t index() const {
return static_cast<size_t>(type_); return static_cast<size_t>(type_);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment