template<typename _Tp>
class optional;
- template<typename>
- struct __is_optional_impl : false_type
- { };
-
- template<typename _Tp>
- struct __is_optional_impl<optional<_Tp>> : true_type
- { };
-
- template<typename _Tp>
- struct __is_optional
- : public __is_optional_impl<std::remove_cv_t<std::remove_reference_t<_Tp>>>
- { };
-
+ template<typename _Tp, typename _Up>
+ using __converts_from_optional =
+ __or_<is_constructible<_Tp, const optional<_Up>&>,
+ is_constructible<_Tp, optional<_Up>&>,
+ is_constructible<_Tp, const optional<_Up>&&>,
+ is_constructible<_Tp, optional<_Up>&&>,
+ is_convertible<const optional<_Up>&, _Tp>,
+ is_convertible<optional<_Up>&, _Tp>,
+ is_convertible<const optional<_Up>&&, _Tp>,
+ is_convertible<optional<_Up>&&, _Tp>>;
+
+ template<typename _Tp, typename _Up>
+ using __assigns_from_optional =
+ __or_<is_assignable<_Tp&, const optional<_Up>&>,
+ is_assignable<_Tp&, optional<_Up>&>,
+ is_assignable<_Tp&, const optional<_Up>&&>,
+ is_assignable<_Tp&, optional<_Up>&&>>;
/**
* @brief Class template for optional values.
// Converting constructors for engaged optionals.
template <typename _Up = _Tp,
enable_if_t<__and_<
- __not_<__is_optional<decay_t<_Up>>>,
+ __not_<is_same<optional<_Tp>, decay_t<_Up>>>,
is_constructible<_Tp, _Up&&>,
is_convertible<_Up&&, _Tp>
>::value, bool> = true>
template <typename _Up = _Tp,
enable_if_t<__and_<
- __not_<__is_optional<decay_t<_Up>>>,
+ __not_<is_same<optional<_Tp>, decay_t<_Up>>>,
is_constructible<_Tp, _Up&&>,
__not_<is_convertible<_Up&&, _Tp>>
>::value, bool> = false>
enable_if_t<__and_<
__not_<is_same<_Tp, _Up>>,
is_constructible<_Tp, const _Up&>,
- is_convertible<const _Up&, _Tp>
+ is_convertible<const _Up&, _Tp>,
+ __not_<__converts_from_optional<_Tp, _Up>>
>::value, bool> = true>
constexpr optional(const optional<_Up>& __t)
: _Base(__t ? _Base(std::in_place, *__t) : _Base()) { }
enable_if_t<__and_<
__not_<is_same<_Tp, _Up>>,
is_constructible<_Tp, const _Up&>,
- __not_<is_convertible<const _Up&, _Tp>>
+ __not_<is_convertible<const _Up&, _Tp>>,
+ __not_<__converts_from_optional<_Tp, _Up>>
>::value, bool> = false>
explicit constexpr optional(const optional<_Up>& __t)
: _Base(__t ? _Base(std::in_place, *__t) : _Base()) { }
enable_if_t<__and_<
__not_<is_same<_Tp, _Up>>,
is_constructible<_Tp, _Up&&>,
- is_convertible<_Up&&, _Tp>
+ is_convertible<_Up&&, _Tp>,
+ __not_<__converts_from_optional<_Tp, _Up>>
>::value, bool> = true>
constexpr optional(optional<_Up>&& __t)
: _Base(__t ? _Base(std::in_place, std::move(*__t)) : _Base()) { }
enable_if_t<__and_<
__not_<is_same<_Tp, _Up>>,
is_constructible<_Tp, _Up&&>,
- __not_<is_convertible<_Up&&, _Tp>>
+ __not_<is_convertible<_Up&&, _Tp>>,
+ __not_<__converts_from_optional<_Tp, _Up>>
>::value, bool> = false>
explicit constexpr optional(optional<_Up>&& __t)
: _Base(__t ? _Base(std::in_place, std::move(*__t)) : _Base()) { }
template<typename _Up = _Tp,
enable_if_t<__and_<
- __not_<__is_optional<decay_t<_Up>>>,
+ __not_<is_same<optional<_Tp>, decay_t<_Up>>>,
is_constructible<_Tp, _Up>,
+ __not_<__and_<is_scalar<_Tp>,
+ is_same<_Tp, decay_t<_Up>>>>,
is_assignable<_Tp&, _Up>>::value,
bool> = true>
optional&
template<typename _Up,
enable_if_t<__and_<
__not_<is_same<_Tp, _Up>>,
- is_constructible<_Tp, _Up>,
- is_assignable<_Tp&, _Up>>::value,
+ is_constructible<_Tp, const _Up&>,
+ is_assignable<_Tp&, _Up>,
+ __not_<__converts_from_optional<_Tp, _Up>>,
+ __not_<__assigns_from_optional<_Tp, _Up>>
+ >::value,
bool> = true>
optional&
operator=(const optional<_Up>& __u)
enable_if_t<__and_<
__not_<is_same<_Tp, _Up>>,
is_constructible<_Tp, _Up>,
- is_assignable<_Tp&, _Up>>::value,
+ is_assignable<_Tp&, _Up>,
+ __not_<__converts_from_optional<_Tp, _Up>>,
+ __not_<__assigns_from_optional<_Tp, _Up>>
+ >::value,
bool> = true>
optional&
operator=(optional<_Up>&& __u)
--- /dev/null
+// { dg-options "-std=gnu++17" }
+// { dg-do run }
+
+// Copyright (C) 2016 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a moved_to of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <exception>
+#include <optional>
+#include <any>
+
+using std::optional;
+
+#include <testsuite_hooks.h>
+
+void test01()
+{
+ optional<optional<std::exception_ptr>> nested_element;
+ optional<std::exception_ptr> element = {};
+ nested_element = element;
+ VERIFY(nested_element);
+}
+
+template <class T>
+struct service_result
+{
+ static optional<T> get_result()
+ {
+ T sr;
+ return sr;
+ }
+
+ static optional<T> get_result_with_cond(bool cond)
+ {
+ if (cond)
+ return T{};
+ return {};
+ }
+};
+
+void test02()
+{
+ VERIFY(service_result<int>::get_result());
+ VERIFY(service_result<optional<int>>::get_result());
+ VERIFY(service_result<int>::get_result_with_cond(true));
+ VERIFY(service_result<optional<int>>::get_result_with_cond(true));
+ VERIFY(!service_result<int>::get_result_with_cond(false));
+ VERIFY(!service_result<optional<int>>::get_result_with_cond(false));
+}
+
+struct Widget
+{
+ Widget(int) {}
+ Widget(optional<int>) {}
+};
+
+
+void test03()
+{
+ optional<Widget> w;
+ w = optional<int>();
+ VERIFY(w);
+ static_assert(!std::is_assignable_v<optional<Widget>&,
+ optional<short>>);;
+ w = optional<optional<int>>();
+ VERIFY(!w);
+ static_assert(!std::is_assignable_v<optional<Widget>&,
+ optional<optional<short>>>);;
+
+ optional<Widget> w2{optional<int>()};
+ VERIFY(w2);
+ optional<Widget> w3 = optional<int>();
+ VERIFY(w3);
+ optional<Widget> w4{optional<short>()};
+ VERIFY(w4);
+ static_assert(!std::is_convertible_v<optional<short>&&, optional<Widget>>);
+
+ optional<Widget> w6{optional<optional<int>>()};
+ VERIFY(!w6);
+ optional<Widget> w7 = optional<optional<int>>();
+ VERIFY(!w7);
+ optional<Widget> w8{optional<optional<short>>()};
+ VERIFY(!w8);
+ static_assert(!std::is_convertible_v<optional<optional<short>>&&,
+ optional<Widget>>);
+ optional<Widget> w10{optional<optional<short>>(10)};
+ VERIFY(w10);
+ optional<Widget> w11 = std::nullopt;
+ VERIFY(!w11);
+ optional<Widget> w12 = {};
+ VERIFY(!w12);
+ optional<Widget> w13{std::nullopt};
+ VERIFY(!w13);
+ optional<Widget> w14;
+ w14 = {};
+ VERIFY(!w14);
+}
+
+struct Widget2
+{
+ Widget2(int) {}
+ Widget2(optional<int>) {}
+ Widget2& operator=(int) {return *this;}
+ Widget2& operator=(optional<int>) {return *this;}
+};
+
+void test04()
+{
+ optional<Widget2> w;
+ w = optional<int>();
+ VERIFY(w);
+ w = optional<short>();
+ VERIFY(w);
+ w = optional<optional<int>>();
+ VERIFY(!w);
+ w = optional<optional<short>>();
+ VERIFY(!w);
+ w = optional<optional<short>>(10);
+ optional<Widget2> w2 = std::nullopt;
+ VERIFY(!w2);
+ optional<Widget2> w3 = {};
+ VERIFY(!w3);
+ optional<Widget2> w4{std::nullopt};
+ VERIFY(!w4);
+ optional<Widget2> w5;
+ w5 = {};
+ VERIFY(!w5);
+}
+
+struct Thingy
+{
+ Thingy(int) {}
+ Thingy(Widget) {}
+};
+
+void test05()
+{
+ optional<Thingy> ot;
+
+ static_assert(!std::is_assignable_v<optional<Thingy>&,
+ optional<int>>);
+ static_assert(std::is_assignable_v<optional<Thingy>&,
+ optional<short>>);
+ static_assert(!std::is_assignable_v<optional<Thingy>&,
+ optional<optional<int>>>);
+ ot = optional<Widget>();
+ VERIFY(!ot);
+ optional<Thingy> ot2{optional<int>()};
+ VERIFY(ot2);
+ static_assert(!std::is_convertible_v<optional<int>&&,
+ optional<Thingy>>);
+ optional<Thingy> ot3{optional<short>()};
+ VERIFY(!ot3);
+ optional<Thingy> ot4 = optional<short>();
+ VERIFY(!ot4);
+
+ optional<Thingy> ot5{optional<optional<int>>()};
+ VERIFY(!ot5);
+ static_assert(!std::is_convertible_v<optional<optional<int>>&&,
+ optional<Thingy>>);
+
+ optional<Thingy> ot7{optional<Widget>()};
+ VERIFY(!ot7);
+ optional<Thingy> ot8 = optional<Widget>();
+ VERIFY(!ot8);
+ static_assert(!std::is_constructible_v<optional<Thingy>,
+ optional<optional<short>>>);
+ static_assert(!std::is_convertible_v<optional<optional<short>>,
+ optional<Thingy>>);
+ static_assert(!std::is_assignable_v<optional<Thingy>&,
+ optional<optional<short>>>);
+ optional<Thingy> ot9 = std::nullopt;
+ VERIFY(!ot9);
+ optional<Thingy> ot10 = {};
+ VERIFY(!ot10);
+ optional<Thingy> ot11{std::nullopt};
+ VERIFY(!ot11);
+ optional<Thingy> ot12;
+ ot12 = {};
+ VERIFY(!ot12);
+}
+
+struct RvalueConstructible
+{
+ RvalueConstructible(int) {}
+ RvalueConstructible(optional<int>&&) {}
+};
+
+void test06()
+{
+ optional<int> oi;
+ optional<RvalueConstructible> ori;
+ static_assert(!std::is_assignable_v<optional<RvalueConstructible>&,
+ optional<int>&>);
+ ori = std::move(oi);
+ VERIFY(ori);
+
+ optional<optional<int>> ooi;
+ static_assert(!std::is_assignable_v<optional<RvalueConstructible>&,
+ optional<optional<int>>&>);
+ ori = std::move(ooi);
+ VERIFY(!ori);
+
+ static_assert(!std::is_constructible_v<optional<RvalueConstructible>,
+ optional<int>&>);
+ static_assert(!std::is_convertible_v<optional<int>&,
+ optional<RvalueConstructible>>);
+
+ optional<RvalueConstructible> ori2(std::move(oi));
+ VERIFY(ori2);
+ optional<RvalueConstructible> ori3 = std::move(oi);
+ VERIFY(ori3);
+
+ static_assert(!std::is_constructible_v<optional<RvalueConstructible>,
+ optional<optional<int>>&>);
+ static_assert(!std::is_convertible_v<optional<optional<int>>&,
+ optional<RvalueConstructible>>);
+ optional<RvalueConstructible> ori6(std::move(ooi));
+ VERIFY(!ori6);
+ optional<RvalueConstructible> ori7 = std::move(ooi);
+ VERIFY(!ori7);
+ optional<RvalueConstructible> ori8 = std::nullopt;
+ VERIFY(!ori8);
+ optional<RvalueConstructible> ori9 = {};
+ VERIFY(!ori9);
+ optional<RvalueConstructible> ori10{std::nullopt};
+ VERIFY(!ori10);
+ optional<RvalueConstructible> ori11;
+ ori11 = {};
+ VERIFY(!ori11);
+}
+
+struct Thingy2
+{
+ Thingy2(int) {}
+ explicit Thingy2(optional<int>) {}
+ Thingy2(Widget) {}
+};
+
+void test07()
+{
+ optional<Thingy2> ot{optional<int>{}};
+ VERIFY(ot);
+ static_assert(!std::is_convertible_v<optional<int>,
+ optional<Thingy2>>);
+ optional<Thingy2> ot2{optional<short>{}};
+ VERIFY(ot2);
+ static_assert(!std::is_convertible_v<optional<short>,
+ optional<Thingy2>>);
+ optional<Thingy2> ot3{optional<optional<int>>{}};
+ VERIFY(!ot3);
+ static_assert(!std::is_convertible_v<optional<optional<int>>,
+ optional<Thingy2>>);
+ optional<Thingy2> ot4{optional<optional<short>>{}};
+ VERIFY(!ot4);
+ static_assert(!std::is_convertible_v<optional<optional<short>>,
+ optional<Thingy2>>);
+
+ optional<Thingy2> ot5{optional<Widget>{}};
+ VERIFY(!ot5);
+ optional<Thingy2> ot6 = optional<Widget>();
+ VERIFY(!ot6);
+
+ static_assert(!std::is_assignable_v<optional<Thingy2>&,
+ optional<int>>);
+ static_assert(!std::is_assignable_v<optional<Thingy2>&,
+ optional<short>>);
+ static_assert(!std::is_assignable_v<optional<Thingy2>&,
+ optional<optional<int>>>);
+ static_assert(!std::is_assignable_v<optional<Thingy2>&,
+ optional<optional<short>>>);
+ optional<Thingy2> ot7;
+ ot = optional<Widget>();
+ VERIFY(!ot7);
+ optional<Thingy2> ot8 = std::nullopt;
+ VERIFY(!ot8);
+ optional<Thingy2> ot9 = {};
+ VERIFY(!ot9);
+ optional<Thingy2> ot10{std::nullopt};
+ VERIFY(!ot10);
+ optional<Thingy2> ot11;
+ ot11 = {};
+ VERIFY(!ot11);
+}
+
+struct Thingy3
+{
+ Thingy3(int) {}
+ template<class... Args,
+ std::enable_if_t<std::is_constructible_v<Widget, Args&&...>,
+ bool> = true>
+ explicit Thingy3(Args&&... args) {}
+ Thingy3(Widget) {}
+};
+
+void test08()
+{
+ optional<Thingy3> ot{optional<int>{}};
+ VERIFY(ot);
+ static_assert(!std::is_convertible_v<optional<int>,
+ optional<Thingy3>>);
+ optional<Thingy3> ot2{optional<short>{}};
+ VERIFY(ot2);
+ static_assert(!std::is_convertible_v<optional<short>,
+ optional<Thingy3>>);
+ optional<Thingy3> ot3{optional<optional<int>>{}};
+ VERIFY(!ot3);
+ static_assert(!std::is_convertible_v<optional<optional<int>>,
+ optional<Thingy3>>);
+ optional<Thingy3> ot4{optional<optional<short>>{}};
+ VERIFY(!ot4);
+ static_assert(!std::is_convertible_v<optional<optional<short>>,
+ optional<Thingy3>>);
+
+ optional<Thingy3> ot5{optional<Widget>{}};
+ VERIFY(!ot5);
+ optional<Thingy3> ot6 = optional<Widget>();
+ VERIFY(!ot6);
+
+ static_assert(!std::is_assignable_v<optional<Thingy3>&,
+ optional<int>>);
+ static_assert(!std::is_assignable_v<optional<Thingy3>&,
+ optional<short>>);
+ static_assert(!std::is_assignable_v<optional<Thingy3>&,
+ optional<optional<int>>>);
+ static_assert(!std::is_assignable_v<optional<Thingy3>&,
+ optional<optional<short>>>);
+ optional<Thingy3> ot7;
+ ot = optional<Widget>();
+ VERIFY(!ot7);
+ optional<Thingy3> ot8 = std::nullopt;
+ VERIFY(!ot8);
+ optional<Thingy3> ot9 = {};
+ VERIFY(!ot9);
+ optional<Thingy3> ot10{std::nullopt};
+ VERIFY(!ot10);
+ optional<Thingy3> ot11;
+ ot11 = {};
+ VERIFY(!ot11);
+}
+
+void test09()
+{
+ std::any a = 42;
+ optional<std::any> oa2 = a;
+ VERIFY(oa2);
+ VERIFY(std::any_cast<int>(*oa2) == 42);
+ optional<std::any> oa3 = oa2;
+ VERIFY(oa3);
+ VERIFY(std::any_cast<int>(*oa3) == 42);
+ optional<std::any> oa4{oa2};
+ VERIFY(oa4);
+ VERIFY(std::any_cast<int>(*oa4) == 42);
+ optional<std::any> oa5(oa2);
+ VERIFY(oa5);
+ VERIFY(std::any_cast<int>(*oa5) == 42);
+ optional<std::any> oa6;
+ VERIFY(!oa6);
+ optional<std::any> oa7 = oa6;
+ VERIFY(!oa7);
+ optional<std::any> oa8{oa6};
+ VERIFY(!oa8);
+ optional<std::any> oa9(oa6);
+ VERIFY(!oa9);
+}
+
+void test10()
+{
+ struct X {};
+ optional<int> oi(std::in_place);
+ oi = {};
+ VERIFY(oi.has_value() == false);
+ optional<X> ot(std::in_place);
+ ot = {};
+ VERIFY(ot.has_value() == false);
+ optional<int> oi2(std::in_place);
+ short int si = 6;
+ oi2 = si;
+}
+
+int main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+ test05();
+ test06();
+ test07();
+ test08();
+ test09();
+ test10();
+}