https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91788

Jonathan Wakely <redi at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|UNCONFIRMED                 |NEW
   Last reconfirmed|                            |2019-09-23
     Ever confirmed|0                           |1

--- Comment #2 from Jonathan Wakely <redi at gcc dot gnu.org> ---
(In reply to Marc Glisse from comment #0)
> IIUC, the whole +1-1 is here so that for a valueless variant, index_type(-1)
> becomes size_t(-1).

You do understand correctly :-)

> I think there are cases where we could do better. For
> instance, for a never valueless type, we could just return _M_index. If
> there are fewer than 128 alternatives, we could use a sign extension:
> "return (signed char)_M_index;".

I think we can do that more generically. Does this look right?

--- a/libstdc++-v3/include/std/variant
+++ b/libstdc++-v3/include/std/variant
@@ -1518,7 +1518,14 @@ namespace __variant
       { return !this->_M_valid(); }

       constexpr size_t index() const noexcept
-      { return size_t(typename _Base::__index_type(this->_M_index + 1)) - 1; }
+      {
+       using __index_type = typename _Base::__index_type;
+       if constexpr (__detail::__variant::__never_valueless<_Types...>())
+         return this->_M_index;
+       else if constexpr (sizeof...(_Types) <= __index_type(-1) / 2)
+         return make_signed_t<__index_type>(this->_M_index);
+       return size_t(typename _Base::__index_type(this->_M_index + 1)) - 1;
+      }

       void
       swap(variant& __rhs)



(In reply to Marc Glisse from comment #1)
> Internally, it may also be possible to avoid calling index() so often and
> work with the raw _M_index more often.

IIRC I considered that, but (at the time) decided to play it safe rather than
spend more time analysing what could be done.

I think we could replace checks like this in get<_Np>:

  if (__v.index() == _Np)

with:

  static_assert(index_type(_Np) == _Np && _Np != index_type(-1));
  if (__v._M_index == _Np)

And in many (most?) cases the static assert is unnecessary because we already
check something like:

       static_assert(_Np < sizeof...(_Types),
                    "The index must be in [0, number of alternatives)");

Anywhere we test equality of index() with a value that is known to be in range,
it's OK to use index_type(-1) directly instead of extending it to size_t(-1).
(The downside would be that many more functions might need to be friends to
access _M_index).

The relational operators need a bit more thought and I don't think we can
change the calls to index() in __do_visit without breaking the implied contract
with the _M_access functions in the "vtable".

Reply via email to