Skip to content

Commit

Permalink
<tuple>, <variant>: Make error messages from get-by-type function…
Browse files Browse the repository at this point in the history
…s clearer (#4578)

Co-authored-by: Stephan T. Lavavej <[email protected]>
  • Loading branch information
frederick-vs-ja and StephanTLavavej authored Apr 12, 2024
1 parent 213df0c commit 9aca224
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 82 deletions.
39 changes: 39 additions & 0 deletions stl/inc/__msvc_iter_core.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,45 @@ struct iterator_traits : _Iterator_traits_base<_Iter> {}; // get traits from ite
template <class _Ty>
struct iterator_traits<_Ty*> : _Iterator_traits_pointer_base<_Ty> {}; // get traits from pointer, if possible
#endif // ^^^ !_HAS_CXX20 ^^^

_INLINE_VAR constexpr auto _Meta_npos = ~size_t{0};

constexpr size_t _Meta_find_index_i_(const bool* const _Ptr, const size_t _Count, size_t _Idx = 0) {
// return the index of the first true in the _Count bools at _Ptr, or _Meta_npos if all are false
for (; _Idx < _Count; ++_Idx) {
if (_Ptr[_Idx]) {
return _Idx;
}
}

return _Meta_npos;
}

template <class _List, class _Ty>
struct _Meta_find_unique_index_ {
using type = integral_constant<size_t, _Meta_npos>;
};
template <class _List, class _Ty>
using _Meta_find_unique_index =
// The index of _Ty in _List if it occurs exactly once, otherwise _Meta_npos
typename _Meta_find_unique_index_<_List, _Ty>::type;

constexpr size_t _Meta_find_unique_index_i_2(const bool* const _Ptr, const size_t _Count, const size_t _First) {
// return _First if there is no _First < j < _Count such that _Ptr[j] is true, otherwise _Meta_npos
return _First != _Meta_npos && _STD _Meta_find_index_i_(_Ptr, _Count, _First + 1) == _Meta_npos ? _First
: _Meta_npos;
}

constexpr size_t _Meta_find_unique_index_i_(const bool* const _Ptr, const size_t _Count) {
// Pass the smallest i such that _Ptr[i] is true to _Meta_find_unique_index_i_2
return _STD _Meta_find_unique_index_i_2(_Ptr, _Count, _STD _Meta_find_index_i_(_Ptr, _Count));
}

template <template <class...> class _List, class _First, class... _Rest, class _Ty>
struct _Meta_find_unique_index_<_List<_First, _Rest...>, _Ty> {
static constexpr bool _Bools[] = {is_same_v<_First, _Ty>, is_same_v<_Rest, _Ty>...};
using type = integral_constant<size_t, _STD _Meta_find_unique_index_i_(_Bools, 1 + sizeof...(_Rest))>;
};
_STD_END

#pragma pop_macro("new")
Expand Down
54 changes: 32 additions & 22 deletions stl/inc/tuple
Original file line number Diff line number Diff line change
Expand Up @@ -913,20 +913,6 @@ constexpr void swap(const tuple<_Types...>& _Left, const tuple<_Types...>& _Righ
}
#endif // _HAS_CXX23

template <class _Ty, class _Tuple>
struct _Tuple_element {}; // backstop _Tuple_element definition

template <class _This, class... _Rest>
struct _Tuple_element<_This, tuple<_This, _Rest...>> { // select first element
static_assert(!_Is_any_of_v<_This, _Rest...>, "duplicate type T in get<T>(tuple)");
using _Ttype = tuple<_This, _Rest...>;
};

template <class _Ty, class _This, class... _Rest>
struct _Tuple_element<_Ty, tuple<_This, _Rest...>> { // recursive _Tuple_element definition
using _Ttype = typename _Tuple_element<_Ty, tuple<_Rest...>>::_Ttype;
};

_EXPORT_STD template <size_t _Index, class... _Types>
_NODISCARD constexpr tuple_element_t<_Index, tuple<_Types...>>& get(tuple<_Types...>& _Tuple) noexcept {
using _Ttype = typename tuple_element<_Index, tuple<_Types...>>::_Ttype;
Expand Down Expand Up @@ -963,26 +949,50 @@ _NODISCARD constexpr auto&& _Tuple_get(tuple<_Types...>&& _Tuple) noexcept {

_EXPORT_STD template <class _Ty, class... _Types>
_NODISCARD constexpr _Ty& get(tuple<_Types...>& _Tuple) noexcept {
using _Ttype = typename _Tuple_element<_Ty, tuple<_Types...>>::_Ttype;
return static_cast<_Ttype&>(_Tuple)._Myfirst._Val;
constexpr size_t _Idx = _Meta_find_unique_index<tuple<_Types...>, _Ty>::value;
if constexpr (_Idx < sizeof...(_Types)) {
using _Ttype = typename tuple_element<_Idx, tuple<_Types...>>::_Ttype;
return static_cast<_Ttype&>(_Tuple)._Myfirst._Val;
} else {
static_assert(_Always_false<_Ty>,
"get<T>(tuple<Types...>&) requires T to occur exactly once in Types. (N4971 [tuple.elem]/5)");
}
}

_EXPORT_STD template <class _Ty, class... _Types>
_NODISCARD constexpr const _Ty& get(const tuple<_Types...>& _Tuple) noexcept {
using _Ttype = typename _Tuple_element<_Ty, tuple<_Types...>>::_Ttype;
return static_cast<const _Ttype&>(_Tuple)._Myfirst._Val;
constexpr size_t _Idx = _Meta_find_unique_index<tuple<_Types...>, _Ty>::value;
if constexpr (_Idx < sizeof...(_Types)) {
using _Ttype = typename tuple_element<_Idx, tuple<_Types...>>::_Ttype;
return static_cast<const _Ttype&>(_Tuple)._Myfirst._Val;
} else {
static_assert(_Always_false<_Ty>,
"get<T>(const tuple<Types...>&) requires T to occur exactly once in Types. (N4971 [tuple.elem]/5)");
}
}

_EXPORT_STD template <class _Ty, class... _Types>
_NODISCARD constexpr _Ty&& get(tuple<_Types...>&& _Tuple) noexcept {
using _Ttype = typename _Tuple_element<_Ty, tuple<_Types...>>::_Ttype;
return static_cast<_Ty&&>(static_cast<_Ttype&>(_Tuple)._Myfirst._Val);
constexpr size_t _Idx = _Meta_find_unique_index<tuple<_Types...>, _Ty>::value;
if constexpr (_Idx < sizeof...(_Types)) {
using _Ttype = typename tuple_element<_Idx, tuple<_Types...>>::_Ttype;
return static_cast<_Ty&&>(static_cast<_Ttype&>(_Tuple)._Myfirst._Val);
} else {
static_assert(_Always_false<_Ty>,
"get<T>(tuple<Types...>&&) requires T to occur exactly once in Types. (N4971 [tuple.elem]/5)");
}
}

_EXPORT_STD template <class _Ty, class... _Types>
_NODISCARD constexpr const _Ty&& get(const tuple<_Types...>&& _Tuple) noexcept {
using _Ttype = typename _Tuple_element<_Ty, tuple<_Types...>>::_Ttype;
return static_cast<const _Ty&&>(static_cast<const _Ttype&>(_Tuple)._Myfirst._Val);
constexpr size_t _Idx = _Meta_find_unique_index<tuple<_Types...>, _Ty>::value;
if constexpr (_Idx < sizeof...(_Types)) {
using _Ttype = typename tuple_element<_Idx, tuple<_Types...>>::_Ttype;
return static_cast<const _Ty&&>(static_cast<const _Ttype&>(_Tuple)._Myfirst._Val);
} else {
static_assert(_Always_false<_Ty>,
"get<T>(const tuple<Types...>&&) requires T to occur exactly once in Types. (N4971 [tuple.elem]/5)");
}
}

template <class _This, class... _Rest>
Expand Down
102 changes: 42 additions & 60 deletions stl/inc/variant
Original file line number Diff line number Diff line change
Expand Up @@ -168,45 +168,6 @@ struct _Meta_at_<_List<_Types...>, _Idx, enable_if_t<(_Idx < sizeof...(_Types))>
};
#endif // ^^^ !defined(__clang__) ^^^

inline constexpr auto _Meta_npos = ~size_t{0};

constexpr size_t _Meta_find_index_i_(const bool* const _Ptr, const size_t _Count, size_t _Idx = 0) {
// return the index of the first true in the _Count bools at _Ptr, or _Meta_npos if all are false
for (; _Idx < _Count; ++_Idx) {
if (_Ptr[_Idx]) {
return _Idx;
}
}

return _Meta_npos;
}

template <class _List, class _Ty>
struct _Meta_find_unique_index_ {
using type = integral_constant<size_t, _Meta_npos>;
};
template <class _List, class _Ty>
using _Meta_find_unique_index =
// The index of _Ty in _List if it occurs exactly once, otherwise _Meta_npos
typename _Meta_find_unique_index_<_List, _Ty>::type;

constexpr size_t _Meta_find_unique_index_i_2(const bool* const _Ptr, const size_t _Count, const size_t _First) {
// return _First if there is no _First < j < _Count such that _Ptr[j] is true, otherwise _Meta_npos
return _First != _Meta_npos && _STD _Meta_find_index_i_(_Ptr, _Count, _First + 1) == _Meta_npos ? _First
: _Meta_npos;
}

constexpr size_t _Meta_find_unique_index_i_(const bool* const _Ptr, const size_t _Count) {
// Pass the smallest i such that _Ptr[i] is true to _Meta_find_unique_index_i_2
return _STD _Meta_find_unique_index_i_2(_Ptr, _Count, _STD _Meta_find_index_i_(_Ptr, _Count));
}

template <template <class...> class _List, class _First, class... _Rest, class _Ty>
struct _Meta_find_unique_index_<_List<_First, _Rest...>, _Ty> {
static constexpr bool _Bools[] = {is_same_v<_First, _Ty>, is_same_v<_Rest, _Ty>...};
using type = integral_constant<size_t, _STD _Meta_find_unique_index_i_(_Bools, 1 + sizeof...(_Rest))>;
};

template <class>
struct _Meta_as_list_;
template <class _Ty>
Expand Down Expand Up @@ -1179,9 +1140,12 @@ _EXPORT_STD template <class _Ty, class... _Types>
_NODISCARD constexpr bool holds_alternative(const variant<_Types...>& _Var) noexcept {
// true iff _Var holds alternative _Ty
constexpr size_t _Idx = _Meta_find_unique_index<variant<_Types...>, _Ty>::value;
static_assert(_Idx != _Meta_npos, "holds_alternative<T>(const variant<Types...>&) requires T to occur exactly "
"once in Types. (N4950 [variant.get]/1)");
return _Var.index() == _Idx;
if constexpr (_Idx != _Meta_npos) {
return _Var.index() == _Idx;
} else {
static_assert(_Always_false<_Ty>, "holds_alternative<T>(const variant<Types...>&) requires T to occur exactly "
"once in Types. (N4971 [variant.get]/1)");
}
}

_EXPORT_STD template <size_t _Idx, class... _Types>
Expand Down Expand Up @@ -1229,33 +1193,45 @@ _EXPORT_STD template <class _Ty, class... _Types>
_NODISCARD constexpr decltype(auto) get(variant<_Types...>& _Var) {
// access the contained value of _Var if its alternative _Ty is active
constexpr size_t _Idx = _Meta_find_unique_index<variant<_Types...>, _Ty>::value;
static_assert(_Idx < sizeof...(_Types),
"get<T>(variant<Types...>&) requires T to occur exactly once in Types. (N4950 [variant.get]/5)");
return _STD get<_Idx>(_Var);
if constexpr (_Idx < sizeof...(_Types)) {
return _STD get<_Idx>(_Var);
} else {
static_assert(_Always_false<_Ty>,
"get<T>(variant<Types...>&) requires T to occur exactly once in Types. (N4971 [variant.get]/8)");
}
}
_EXPORT_STD template <class _Ty, class... _Types>
_NODISCARD constexpr decltype(auto) get(variant<_Types...>&& _Var) {
// access the contained value of _Var if its alternative _Ty is active
constexpr size_t _Idx = _Meta_find_unique_index<variant<_Types...>, _Ty>::value;
static_assert(_Idx < sizeof...(_Types),
"get<T>(variant<Types...>&&) requires T to occur exactly once in Types. (N4950 [variant.get]/5)");
return _STD get<_Idx>(_STD move(_Var));
if constexpr (_Idx < sizeof...(_Types)) {
return _STD get<_Idx>(_STD move(_Var));
} else {
static_assert(_Always_false<_Ty>,
"get<T>(variant<Types...>&&) requires T to occur exactly once in Types. (N4971 [variant.get]/8)");
}
}
_EXPORT_STD template <class _Ty, class... _Types>
_NODISCARD constexpr decltype(auto) get(const variant<_Types...>& _Var) {
// access the contained value of _Var if its alternative _Ty is active
constexpr size_t _Idx = _Meta_find_unique_index<variant<_Types...>, _Ty>::value;
static_assert(_Idx < sizeof...(_Types),
"get<T>(const variant<Types...>&) requires T to occur exactly once in Types. (N4950 [variant.get]/5)");
return _STD get<_Idx>(_Var);
if constexpr (_Idx < sizeof...(_Types)) {
return _STD get<_Idx>(_Var);
} else {
static_assert(_Always_false<_Ty>,
"get<T>(const variant<Types...>&) requires T to occur exactly once in Types. (N4971 [variant.get]/8)");
}
}
_EXPORT_STD template <class _Ty, class... _Types>
_NODISCARD constexpr decltype(auto) get(const variant<_Types...>&& _Var) {
// access the contained value of _Var if its alternative _Ty is active
constexpr size_t _Idx = _Meta_find_unique_index<variant<_Types...>, _Ty>::value;
static_assert(_Idx < sizeof...(_Types),
"get<T>(const variant<Types...>&&) requires T to occur exactly once in Types. (N4950 [variant.get]/5)");
return _STD get<_Idx>(_STD move(_Var));
if constexpr (_Idx < sizeof...(_Types)) {
return _STD get<_Idx>(_STD move(_Var));
} else {
static_assert(_Always_false<_Ty>,
"get<T>(const variant<Types...>&&) requires T to occur exactly once in Types. (N4971 [variant.get]/8)");
}
}

_EXPORT_STD template <size_t _Idx, class... _Types>
Expand All @@ -1275,17 +1251,23 @@ _EXPORT_STD template <class _Ty, class... _Types>
_NODISCARD constexpr add_pointer_t<_Ty> get_if(variant<_Types...>* _Ptr) noexcept {
// get the address of *_Ptr's contained value if it holds alternative _Ty
constexpr size_t _Idx = _Meta_find_unique_index<variant<_Types...>, _Ty>::value;
static_assert(_Idx != _Meta_npos,
"get_if<T>(variant<Types...> *) requires T to occur exactly once in Types. (N4950 [variant.get]/9)");
return _STD get_if<_Idx>(_Ptr);
if constexpr (_Idx != _Meta_npos) {
return _STD get_if<_Idx>(_Ptr);
} else {
static_assert(_Always_false<_Ty>,
"get_if<T>(variant<Types...> *) requires T to occur exactly once in Types. (N4971 [variant.get]/12)");
}
}
_EXPORT_STD template <class _Ty, class... _Types>
_NODISCARD constexpr add_pointer_t<const _Ty> get_if(const variant<_Types...>* _Ptr) noexcept {
// get the address of *_Ptr's contained value if it holds alternative _Ty
constexpr size_t _Idx = _Meta_find_unique_index<variant<_Types...>, _Ty>::value;
static_assert(_Idx != _Meta_npos,
"get_if<T>(const variant<Types...> *) requires T to occur exactly once in Types. (N4950 [variant.get]/9)");
return _STD get_if<_Idx>(_Ptr);
if constexpr (_Idx != _Meta_npos) {
return _STD get_if<_Idx>(_Ptr);
} else {
static_assert(_Always_false<_Ty>,
"get_if<T>(const variant<Types...> *) requires T to occur exactly once in Types. (N4971 [variant.get]/12)");
}
}

template <class _Op, class _Result, class... _Types>
Expand Down

0 comments on commit 9aca224

Please sign in to comment.