__location->~_Tp();
}
-#if __cplusplus > 201703L
+#if __cplusplus >= 202002L
template<typename _Tp, typename... _Args>
constexpr auto
construct_at(_Tp* __location, _Args&&... __args)
*/
#if __cplusplus >= 201103L
template<typename _Tp, typename... _Args>
+ _GLIBCXX20_CONSTEXPR
inline void
_Construct(_Tp* __p, _Args&&... __args)
- { ::new(static_cast<void*>(__p)) _Tp(std::forward<_Args>(__args)...); }
+ {
+#if __cplusplus >= 202002L && __has_builtin(__builtin_is_constant_evaluated)
+ if (__builtin_is_constant_evaluated())
+ {
+ // Allow std::_Construct to be used in constant expressions.
+ std::construct_at(__p, std::forward<_Args>(__args)...);
+ return;
+ }
+#endif
+ ::new(static_cast<void*>(__p)) _Tp(std::forward<_Args>(__args)...);
+ }
#else
template<typename _T1, typename _T2>
inline void
#include <exception>
#include <new>
#include <initializer_list>
+#include <bits/enable_special_members.h>
#include <bits/exception_defines.h>
#include <bits/functional_hash.h>
-#include <bits/enable_special_members.h>
+#include <bits/stl_construct.h> // _Construct
#if __cplusplus > 201703L
# include <compare>
#endif
* @{
*/
-#define __cpp_lib_optional 201606L
+#if __cplusplus == 201703L
+# define __cpp_lib_optional 201606L
+#else
+# define __cpp_lib_optional 202106L
+#endif
template<typename _Tp>
class optional;
{ }
// User-provided destructor is needed when _Up has non-trivial dtor.
- ~_Storage() { }
+ _GLIBCXX20_CONSTEXPR ~_Storage() { }
_Empty_byte _M_empty;
_Up _M_value;
bool _M_engaged = false;
template<typename... _Args>
- void
+ constexpr void
_M_construct(_Args&&... __args)
noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>)
{
- ::new ((void *) std::__addressof(this->_M_payload))
- _Stored_type(std::forward<_Args>(__args)...);
+ std::_Construct(std::__addressof(this->_M_payload._M_value),
+ std::forward<_Args>(__args)...);
this->_M_engaged = true;
}
_Optional_payload& operator=(_Optional_payload&&) = default;
// Destructor needs to destroy the contained value:
- ~_Optional_payload() { this->_M_reset(); }
+ _GLIBCXX20_CONSTEXPR ~_Optional_payload() { this->_M_reset(); }
};
// Common base class for _Optional_base<T> to avoid repeating these
// The _M_construct operation has !_M_engaged as a precondition
// while _M_destruct has _M_engaged as a precondition.
template<typename... _Args>
- void
+ constexpr void
_M_construct(_Args&&... __args)
noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>)
{
- ::new
- (std::__addressof(static_cast<_Dp*>(this)->_M_payload._M_payload))
- _Stored_type(std::forward<_Args>(__args)...);
- static_cast<_Dp*>(this)->_M_payload._M_engaged = true;
+ static_cast<_Dp*>(this)->_M_payload._M_construct(
+ std::forward<_Args>(__args)...);
}
- void
+ constexpr void
_M_destruct() noexcept
{ static_cast<_Dp*>(this)->_M_payload._M_destroy(); }
// Assignment operators.
- optional&
+ _GLIBCXX20_CONSTEXPR optional&
operator=(nullopt_t) noexcept
{
this->_M_reset();
}
template<typename _Up = _Tp>
+ _GLIBCXX20_CONSTEXPR
enable_if_t<__and_v<__not_self<_Up>,
__not_<__and_<is_scalar<_Tp>,
is_same<_Tp, decay_t<_Up>>>>,
}
template<typename _Up>
+ _GLIBCXX20_CONSTEXPR
enable_if_t<__and_v<__not_<is_same<_Tp, _Up>>,
is_constructible<_Tp, const _Up&>,
is_assignable<_Tp&, const _Up&>,
}
template<typename _Up>
+ _GLIBCXX20_CONSTEXPR
enable_if_t<__and_v<__not_<is_same<_Tp, _Up>>,
is_constructible<_Tp, _Up>,
is_assignable<_Tp&, _Up>,
}
template<typename... _Args>
+ _GLIBCXX20_CONSTEXPR
enable_if_t<is_constructible_v<_Tp, _Args...>, _Tp&>
emplace(_Args&&... __args)
noexcept(is_nothrow_constructible_v<_Tp, _Args...>)
}
template<typename _Up, typename... _Args>
+ _GLIBCXX20_CONSTEXPR
enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>,
_Tp&>
emplace(initializer_list<_Up> __il, _Args&&... __args)
// Destructor is implicit, implemented in _Optional_base.
// Swap.
- void
+ _GLIBCXX20_CONSTEXPR void
swap(optional& __other)
noexcept(is_nothrow_move_constructible_v<_Tp>
&& is_nothrow_swappable_v<_Tp>)
return static_cast<_Tp>(std::forward<_Up>(__u));
}
- void reset() noexcept { this->_M_reset(); }
+ _GLIBCXX20_CONSTEXPR void reset() noexcept { this->_M_reset(); }
};
template<typename _Tp>
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 2748. swappable traits for optionals
template<typename _Tp>
+ _GLIBCXX20_CONSTEXPR
inline enable_if_t<is_move_constructible_v<_Tp> && is_swappable_v<_Tp>>
swap(optional<_Tp>& __lhs, optional<_Tp>& __rhs)
noexcept(noexcept(__lhs.swap(__rhs)))
#define __cpp_lib_node_extract 201606
#define __cpp_lib_nonmember_container_access 201411
#define __cpp_lib_not_fn 201603
-#define __cpp_lib_optional 201606L
+#if __cplusplus == 201703L // N.B. updated value in C++20
+# define __cpp_lib_optional 201606L
+#endif
#define __cpp_lib_parallel_algorithm 201603L
#define __cpp_lib_raw_memory_algorithms 201606L
#define __cpp_lib_sample 201603
# define __cpp_lib_make_obj_using_allocator 201811L
#endif
#define __cpp_lib_math_constants 201907L
+#define __cpp_lib_optional 202106L
#define __cpp_lib_polymorphic_allocator 201902L
#if __cpp_lib_concepts
# define __cpp_lib_ranges 201911L
--- /dev/null
+// { dg-options "-std=gnu++20" }
+// { dg-do compile { target c++20 } }
+
+#include <optional>
+#include <testsuite_hooks.h>
+
+
+constexpr bool
+test_assign()
+{
+ std::optional<int> oi(1);
+ std::optional<unsigned> ou(2u), ou3(3u);
+
+ // optional& operator=(nullopt_t);
+ oi = std::nullopt;
+ VERIFY( ! oi.has_value() );
+ oi = std::nullopt;
+ VERIFY( ! oi.has_value() );
+
+ struct S {
+ constexpr S() { }
+ constexpr S(char, int, unsigned) { }
+ };
+ std::optional<S> os1, os2;
+
+ // template<class U = T> optional& operator=(U&&);
+ os1 = {'0', 1, 2u};
+ VERIFY( os1.has_value() );
+ os2 = {'3', 4, 5u};
+ VERIFY( os2.has_value() );
+ oi = 0u;
+ VERIFY( *oi == 0 );
+ oi = 1u;
+ VERIFY( *oi == 1 );
+
+ // template<class U> optional& operator=(const optional<U>&);
+ oi = ou;
+ VERIFY( *oi == 2 );
+ oi = ou3;
+ VERIFY( *oi == 3 );
+
+ // template<class U> optional& operator=(optional<U>&&);
+ oi = std::move(ou);
+ VERIFY( *oi == 2 );
+ oi = std::move(ou);
+ VERIFY( *oi == 2 );
+ oi = std::move(ou3);
+ VERIFY( *oi == 3 );
+
+ return true;
+}
+
+static_assert( test_assign() );
+
+constexpr bool
+test_emplace()
+{
+ struct S
+ {
+ constexpr S(int i) : val(i) { }
+ constexpr S(int i, int j) : val(i + j) { }
+ constexpr S(std::initializer_list<char> l, int i = 0) : val(i)
+ {
+ for (char c : l)
+ val -= c;
+ }
+
+ int val;
+
+ constexpr bool operator==(int i) const { return val == i; }
+ };
+
+
+ std::optional<S> os;
+
+ // template<class... Args> constexpr T& emplace(Args&&...);
+ os.emplace(1);
+ VERIFY( *os == 1 );
+ os.emplace(2);
+ VERIFY( *os == 2 );
+ os.emplace(2, 3);
+ VERIFY( *os == 5 );
+
+ // template<class U, class... Args>
+ // constexpr T& emplace(initializer_list<U>, Args&&...);
+ os.emplace({'3', '4', '5'});
+ VERIFY( *os == -156 );
+ os.emplace({'6', '7', '8'}, 25);
+ VERIFY( *os == -140 );
+
+ return true;
+}
+
+static_assert( test_emplace() );
--- /dev/null
+// { dg-options "-std=gnu++20" }
+// { dg-do compile { target c++20 } }
+
+#include <optional>
+#include <testsuite_hooks.h>
+
+constexpr bool
+test_cons()
+{
+ std::optional<int> oi(1);
+ std::optional<long> ol(oi);
+ VERIFY( *ol == 1L );
+ VERIFY( *oi == 1 );
+
+ std::optional<unsigned> ou(std::move(oi));
+ VERIFY( *ou == 1u );
+ VERIFY( oi.has_value() && *oi == 1 );
+
+ return true;
+}
+
+static_assert( test_cons() );
--- /dev/null
+// { dg-options "-std=gnu++20" }
+// { dg-do compile { target c++20 } }
+
+#include <optional>
+#include <testsuite_hooks.h>
+
+constexpr bool
+test_reset()
+{
+ std::optional<int> oi(1);
+ oi.reset();
+ VERIFY( ! oi.has_value() );
+ oi.reset();
+ VERIFY( ! oi.has_value() );
+
+ return true;
+}
+
+static_assert( test_reset() );
--- /dev/null
+// { dg-options "-std=gnu++20" }
+// { dg-do compile { target c++20 } }
+
+#include <optional>
+#include <testsuite_hooks.h>
+
+constexpr bool
+test_swap()
+{
+ std::optional<int> o0, o1(1);
+ o0.swap(o1);
+ VERIFY( *o0 == 1 );
+ VERIFY( ! o1.has_value() );
+ o0.swap(o1);
+ VERIFY( ! o0.has_value() );
+ VERIFY( *o1 == 1 );
+ o0.swap(o0);
+ VERIFY( ! o0.has_value() );
+ o1.swap(o1);
+ VERIFY( *o1 == 1 );
+ std::optional<int> o2(2);
+ swap(o1, o2);
+ VERIFY( *o1 == 2 );
+ VERIFY( *o2 == 1 );
+
+ return true;
+}
+
+static_assert( test_swap() );
// <http://www.gnu.org/licenses/>.
#include <optional>
+
+#ifndef __cpp_lib_optional
+# error "Feature test macro for optional is missing in <optional>"
+#elif __cpp_lib_optional < 201606L
+# error "Feature test macro for optional has wrong value in <optional>"
+#elif __cplusplus >= 202002L && __cpp_lib_optional < 202106L
+# error "Feature test macro for optional has wrong value for C++20 in <optional>"
+#endif
+
#include <testsuite_hooks.h>
#include <tuple>
--- /dev/null
+// { dg-do compile { target c++17 } }
+
+#include <version>
+
+#ifndef __cpp_lib_optional
+# error "Feature test macro for optional is missing in <version>"
+#elif __cpp_lib_optional < 201606L
+# error "Feature test macro for optional has wrong value in <version>"
+#elif __cplusplus >= 202002L && __cpp_lib_optional < 202106L
+# error "Feature test macro for optional has wrong value for C++20 in <version>"
+#endif