[v3 PATCH] Implement LWG 2900, The copy and move constructors of optional are not constexpr.

Jonathan Wakely jwakely@redhat.com
Tue Mar 28 10:08:00 GMT 2017


On 17/03/17 16:51 +0200, Ville Voutilainen wrote:
>diff --git a/libstdc++-v3/include/std/optional b/libstdc++-v3/include/std/optional
>index 3f540ec..e67ba89 100644
>--- a/libstdc++-v3/include/std/optional
>+++ b/libstdc++-v3/include/std/optional
>@@ -95,125 +95,127 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>-      constexpr _Optional_base(nullopt_t) noexcept
>-      : _Optional_base{} { }
>+      template<typename _Up, typename... _Args>
>+      constexpr _Optional_payload(std::initializer_list<_Up> __il,
>+				  _Args&&... __args)
>+	: _M_payload(__il, std::forward<_Args>(__args)...),
>+	  _M_engaged(true) {}
>+
>+      template <class _Up> struct __ctor_tag {};

Newline here please, so it doesn't look like this template<...> is on
the constructor.

>+      constexpr _Optional_payload(__ctor_tag<bool>,
>+				  const _Tp& __other)
>+	: _M_payload(__other),
>+	  _M_engaged(true)
>+      {}
>+
>+      constexpr _Optional_payload(__ctor_tag<void>)
>+	: _M_empty()
>+      {}
>+
>+      constexpr _Optional_payload(__ctor_tag<bool>, _Tp&& __other)
>+	: _M_payload(std::move(__other)),
>+	  _M_engaged(true)
>+      {}
>+
>+      constexpr _Optional_payload(bool __engaged,
>+				  const _Optional_payload&

Looks like we don't need a newline before the parameter name here:

>+				  __other)
>+	: _Optional_payload(__engaged ?
>+			    _Optional_payload(__ctor_tag<bool>{},
>+					      __other._M_payload) :
>+			    _Optional_payload(__ctor_tag<void>{}))
>+      {}
>+
>+      constexpr _Optional_payload(bool __engaged,
>+				  _Optional_payload&&

Nor here:

>+				  __other)
>+	: _Optional_payload(__engaged ?
>+			    _Optional_payload(__ctor_tag<bool>{},
>+					      std::move(__other._M_payload)) :
>+			    _Optional_payload(__ctor_tag<void>{}))
>+      {}

Hmm, I see we don't actually show a conditional expression in the
Coding Style docs, but I'd do that as:

	: _Optional_payload(__engaged
			    ? _Optional_payload(__ctor_tag<bool>{},
                                                std::move(__other._M_payload))
			    : _Optional_payload(__ctor_tag<void>{}))


>-      // Constructors for engaged optionals.
>-      template<typename... _Args,
>-	       enable_if_t<is_constructible_v<_Tp, _Args&&...>, bool> = false>
>-        constexpr explicit _Optional_base(in_place_t, _Args&&... __args)
>-        : _M_payload(std::forward<_Args>(__args)...), _M_engaged(true) { }
>+      using _Stored_type = remove_const_t<_Tp>;
>+      struct _Empty_byte { };

I was going to ask whether std::byte would be better here, but I think
a valueless struct is better.

>+      union {
>+          _Empty_byte _M_empty;
>+          _Stored_type _M_payload;
>+      };
>+      bool _M_engaged = false;
>+    };


>+      template<typename... _Args>
>+        void
>+        _M_construct(_Args&&... __args)
>+        noexcept(is_nothrow_constructible<_Stored_type, _Args...>())
>+        {
>+          ::new (std::__addressof(this->_M_payload))

I think we need (void*) here to ensure we use the reserved placement
form of operator new and not some other overload:

struct X { };
void* operator new(decltype(sizeof(0)) n, X*);

(We don't get this right everywhere that uses placement new with
arbitrary types).


>+            _Stored_type(std::forward<_Args>(__args)...);
>+          this->_M_engaged = true;
>+        }
>     };
>
>+      // The _M_construct operation has !_M_engaged as a precondition
>+      // while _M_destruct has _M_engaged as a precondition.
>       template<typename... _Args>
>         void
>         _M_construct(_Args&&... __args)
>         noexcept(is_nothrow_constructible<_Stored_type, _Args...>())
>         {
>-          ::new (std::__addressof(this->_M_payload))
>+          ::new (std::__addressof(this->_M_payload._M_payload))

Here too.

>             _Stored_type(std::forward<_Args>(__args)...);
>-          this->_M_engaged = true;
>+          this->_M_payload._M_engaged = true;
>         }

OK for trunk with those adjustements, thanks.



More information about the Gcc-patches mailing list