[v3 PATCH, RFC] Rewrite variant. Also PR libstdc++/85517

Jonathan Wakely jwakely@redhat.com
Wed Mar 6 10:09:00 GMT 2019


On 06/03/19 11:56 +0200, Ville Voutilainen wrote:
>On Wed, 6 Mar 2019 at 11:33, Jonathan Wakely <jwakely@redhat.com> wrote:
>> >+      else if constexpr (is_rvalue_reference_v<_Tp&&>)
>>
>> I know what this is doing, but it still looks a little odd to ask if
>> T&& is an rvalue-reference.
>>
>> Would it be clearer to structure this as:
>>
>>       if constexpr (is_lvalue_reference_v<_Tp>)
>>         {
>>           if constexpr (is_const_v<remove_reference_t<_Tp>>)
>>             return static_cast<const variant<_Types...>&>(__rhs);
>>           else
>>             return static_cast<variant<_Types...>&>(__rhs);
>>         }
>>       else
>>         return static_cast<variant<_Types...>&&>(__rhs);
>>
>> ?
>> >+          ::new (std::addressof(__this_mem))
>>
>> Is there any way that this can find the wrong operator new?
>>
>> Even if it can't, saying ::new ((void*)std::addressof(__this_mem))
>> would avoid having to think about that question again in future.
>>
>> Therre are a few other new expressions where that applies too (several
>> of them already there before your patch).
>> >+      ::new (&__storage) remove_reference_t<decltype(__storage)>
>>
>> This one definitely needs to be cast to void* and needs to use
>> addressof (or __addressof), otherwise ...
>
>
>Sure thing; an incremental diff attached.

>diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant
>index 5138599..4d81ceb 100644
>--- a/libstdc++-v3/include/std/variant
>+++ b/libstdc++-v3/include/std/variant
>@@ -145,12 +145,15 @@ namespace __variant
>   template <typename... _Types, typename _Tp>
>     decltype(auto) __variant_cast(_Tp&& __rhs)
>     {
>-      if constexpr (is_const_v<remove_reference_t<_Tp>>)
>-        return static_cast<const variant<_Types...>&>(__rhs);
>-      else if constexpr (is_rvalue_reference_v<_Tp&&>)
>-        return static_cast<variant<_Types...>&&>(__rhs);
>+      if constexpr (is_lvalue_reference_v<_Tp>)

As you mentioned on IRC, this also seems a bit odd ("why would it be
an lvalue reference?"), but such is the way of forwarding references
... they're not very intuitable. I think I have a weak preference for
doing it this way, so thanks for the change.

>+	{
>+	  if constexpr (is_const_v<remove_reference_t<_Tp>>)
>+			 return static_cast<const variant<_Types...>&>(__rhs);

Too many TABs here.

>+	  else
>+	    return static_cast<variant<_Types...>&>(__rhs);
>+	}
>       else
>-        return static_cast<variant<_Types...>&>(__rhs);
>+        return static_cast<variant<_Types...>&&>(__rhs);
>     }
> 
> namespace __detail
>@@ -212,7 +215,8 @@ namespace __variant
>     {
>       template<typename... _Args>
>       constexpr _Uninitialized(in_place_index_t<0>, _Args&&... __args)
>-      { ::new (&_M_storage) _Type(std::forward<_Args>(__args)...); }
>+      { ::new ((void*)std::addressof(_M_storage))
>+	  _Type(std::forward<_Args>(__args)...); }

Now that it doesn't fit in a single line, please put the braces on
separate lines:

      {
        ::new ((void*)std::addressof(_M_storage))
	  _Type(std::forward<_Args>(__args)...);
      }

Otherwise looks great, OK for trunk with those whitespace tweaks.
Thanks for doing this!




More information about the Libstdc++ mailing list