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".