Skip to content

Commit 9aca224

Browse files
<tuple>, <variant>: Make error messages from get-by-type functions clearer (microsoft#4578)
Co-authored-by: Stephan T. Lavavej <stl@nuwen.net>
1 parent 213df0c commit 9aca224

File tree

3 files changed

+113
-82
lines changed

3 files changed

+113
-82
lines changed

stl/inc/__msvc_iter_core.hpp

+39
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,45 @@ struct iterator_traits : _Iterator_traits_base<_Iter> {}; // get traits from ite
512512
template <class _Ty>
513513
struct iterator_traits<_Ty*> : _Iterator_traits_pointer_base<_Ty> {}; // get traits from pointer, if possible
514514
#endif // ^^^ !_HAS_CXX20 ^^^
515+
516+
_INLINE_VAR constexpr auto _Meta_npos = ~size_t{0};
517+
518+
constexpr size_t _Meta_find_index_i_(const bool* const _Ptr, const size_t _Count, size_t _Idx = 0) {
519+
// return the index of the first true in the _Count bools at _Ptr, or _Meta_npos if all are false
520+
for (; _Idx < _Count; ++_Idx) {
521+
if (_Ptr[_Idx]) {
522+
return _Idx;
523+
}
524+
}
525+
526+
return _Meta_npos;
527+
}
528+
529+
template <class _List, class _Ty>
530+
struct _Meta_find_unique_index_ {
531+
using type = integral_constant<size_t, _Meta_npos>;
532+
};
533+
template <class _List, class _Ty>
534+
using _Meta_find_unique_index =
535+
// The index of _Ty in _List if it occurs exactly once, otherwise _Meta_npos
536+
typename _Meta_find_unique_index_<_List, _Ty>::type;
537+
538+
constexpr size_t _Meta_find_unique_index_i_2(const bool* const _Ptr, const size_t _Count, const size_t _First) {
539+
// return _First if there is no _First < j < _Count such that _Ptr[j] is true, otherwise _Meta_npos
540+
return _First != _Meta_npos && _STD _Meta_find_index_i_(_Ptr, _Count, _First + 1) == _Meta_npos ? _First
541+
: _Meta_npos;
542+
}
543+
544+
constexpr size_t _Meta_find_unique_index_i_(const bool* const _Ptr, const size_t _Count) {
545+
// Pass the smallest i such that _Ptr[i] is true to _Meta_find_unique_index_i_2
546+
return _STD _Meta_find_unique_index_i_2(_Ptr, _Count, _STD _Meta_find_index_i_(_Ptr, _Count));
547+
}
548+
549+
template <template <class...> class _List, class _First, class... _Rest, class _Ty>
550+
struct _Meta_find_unique_index_<_List<_First, _Rest...>, _Ty> {
551+
static constexpr bool _Bools[] = {is_same_v<_First, _Ty>, is_same_v<_Rest, _Ty>...};
552+
using type = integral_constant<size_t, _STD _Meta_find_unique_index_i_(_Bools, 1 + sizeof...(_Rest))>;
553+
};
515554
_STD_END
516555

517556
#pragma pop_macro("new")

stl/inc/tuple

+32-22
Original file line numberDiff line numberDiff line change
@@ -913,20 +913,6 @@ constexpr void swap(const tuple<_Types...>& _Left, const tuple<_Types...>& _Righ
913913
}
914914
#endif // _HAS_CXX23
915915

916-
template <class _Ty, class _Tuple>
917-
struct _Tuple_element {}; // backstop _Tuple_element definition
918-
919-
template <class _This, class... _Rest>
920-
struct _Tuple_element<_This, tuple<_This, _Rest...>> { // select first element
921-
static_assert(!_Is_any_of_v<_This, _Rest...>, "duplicate type T in get<T>(tuple)");
922-
using _Ttype = tuple<_This, _Rest...>;
923-
};
924-
925-
template <class _Ty, class _This, class... _Rest>
926-
struct _Tuple_element<_Ty, tuple<_This, _Rest...>> { // recursive _Tuple_element definition
927-
using _Ttype = typename _Tuple_element<_Ty, tuple<_Rest...>>::_Ttype;
928-
};
929-
930916
_EXPORT_STD template <size_t _Index, class... _Types>
931917
_NODISCARD constexpr tuple_element_t<_Index, tuple<_Types...>>& get(tuple<_Types...>& _Tuple) noexcept {
932918
using _Ttype = typename tuple_element<_Index, tuple<_Types...>>::_Ttype;
@@ -963,26 +949,50 @@ _NODISCARD constexpr auto&& _Tuple_get(tuple<_Types...>&& _Tuple) noexcept {
963949

964950
_EXPORT_STD template <class _Ty, class... _Types>
965951
_NODISCARD constexpr _Ty& get(tuple<_Types...>& _Tuple) noexcept {
966-
using _Ttype = typename _Tuple_element<_Ty, tuple<_Types...>>::_Ttype;
967-
return static_cast<_Ttype&>(_Tuple)._Myfirst._Val;
952+
constexpr size_t _Idx = _Meta_find_unique_index<tuple<_Types...>, _Ty>::value;
953+
if constexpr (_Idx < sizeof...(_Types)) {
954+
using _Ttype = typename tuple_element<_Idx, tuple<_Types...>>::_Ttype;
955+
return static_cast<_Ttype&>(_Tuple)._Myfirst._Val;
956+
} else {
957+
static_assert(_Always_false<_Ty>,
958+
"get<T>(tuple<Types...>&) requires T to occur exactly once in Types. (N4971 [tuple.elem]/5)");
959+
}
968960
}
969961

970962
_EXPORT_STD template <class _Ty, class... _Types>
971963
_NODISCARD constexpr const _Ty& get(const tuple<_Types...>& _Tuple) noexcept {
972-
using _Ttype = typename _Tuple_element<_Ty, tuple<_Types...>>::_Ttype;
973-
return static_cast<const _Ttype&>(_Tuple)._Myfirst._Val;
964+
constexpr size_t _Idx = _Meta_find_unique_index<tuple<_Types...>, _Ty>::value;
965+
if constexpr (_Idx < sizeof...(_Types)) {
966+
using _Ttype = typename tuple_element<_Idx, tuple<_Types...>>::_Ttype;
967+
return static_cast<const _Ttype&>(_Tuple)._Myfirst._Val;
968+
} else {
969+
static_assert(_Always_false<_Ty>,
970+
"get<T>(const tuple<Types...>&) requires T to occur exactly once in Types. (N4971 [tuple.elem]/5)");
971+
}
974972
}
975973

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

982986
_EXPORT_STD template <class _Ty, class... _Types>
983987
_NODISCARD constexpr const _Ty&& get(const tuple<_Types...>&& _Tuple) noexcept {
984-
using _Ttype = typename _Tuple_element<_Ty, tuple<_Types...>>::_Ttype;
985-
return static_cast<const _Ty&&>(static_cast<const _Ttype&>(_Tuple)._Myfirst._Val);
988+
constexpr size_t _Idx = _Meta_find_unique_index<tuple<_Types...>, _Ty>::value;
989+
if constexpr (_Idx < sizeof...(_Types)) {
990+
using _Ttype = typename tuple_element<_Idx, tuple<_Types...>>::_Ttype;
991+
return static_cast<const _Ty&&>(static_cast<const _Ttype&>(_Tuple)._Myfirst._Val);
992+
} else {
993+
static_assert(_Always_false<_Ty>,
994+
"get<T>(const tuple<Types...>&&) requires T to occur exactly once in Types. (N4971 [tuple.elem]/5)");
995+
}
986996
}
987997

988998
template <class _This, class... _Rest>

stl/inc/variant

+42-60
Original file line numberDiff line numberDiff line change
@@ -168,45 +168,6 @@ struct _Meta_at_<_List<_Types...>, _Idx, enable_if_t<(_Idx < sizeof...(_Types))>
168168
};
169169
#endif // ^^^ !defined(__clang__) ^^^
170170

171-
inline constexpr auto _Meta_npos = ~size_t{0};
172-
173-
constexpr size_t _Meta_find_index_i_(const bool* const _Ptr, const size_t _Count, size_t _Idx = 0) {
174-
// return the index of the first true in the _Count bools at _Ptr, or _Meta_npos if all are false
175-
for (; _Idx < _Count; ++_Idx) {
176-
if (_Ptr[_Idx]) {
177-
return _Idx;
178-
}
179-
}
180-
181-
return _Meta_npos;
182-
}
183-
184-
template <class _List, class _Ty>
185-
struct _Meta_find_unique_index_ {
186-
using type = integral_constant<size_t, _Meta_npos>;
187-
};
188-
template <class _List, class _Ty>
189-
using _Meta_find_unique_index =
190-
// The index of _Ty in _List if it occurs exactly once, otherwise _Meta_npos
191-
typename _Meta_find_unique_index_<_List, _Ty>::type;
192-
193-
constexpr size_t _Meta_find_unique_index_i_2(const bool* const _Ptr, const size_t _Count, const size_t _First) {
194-
// return _First if there is no _First < j < _Count such that _Ptr[j] is true, otherwise _Meta_npos
195-
return _First != _Meta_npos && _STD _Meta_find_index_i_(_Ptr, _Count, _First + 1) == _Meta_npos ? _First
196-
: _Meta_npos;
197-
}
198-
199-
constexpr size_t _Meta_find_unique_index_i_(const bool* const _Ptr, const size_t _Count) {
200-
// Pass the smallest i such that _Ptr[i] is true to _Meta_find_unique_index_i_2
201-
return _STD _Meta_find_unique_index_i_2(_Ptr, _Count, _STD _Meta_find_index_i_(_Ptr, _Count));
202-
}
203-
204-
template <template <class...> class _List, class _First, class... _Rest, class _Ty>
205-
struct _Meta_find_unique_index_<_List<_First, _Rest...>, _Ty> {
206-
static constexpr bool _Bools[] = {is_same_v<_First, _Ty>, is_same_v<_Rest, _Ty>...};
207-
using type = integral_constant<size_t, _STD _Meta_find_unique_index_i_(_Bools, 1 + sizeof...(_Rest))>;
208-
};
209-
210171
template <class>
211172
struct _Meta_as_list_;
212173
template <class _Ty>
@@ -1179,9 +1140,12 @@ _EXPORT_STD template <class _Ty, class... _Types>
11791140
_NODISCARD constexpr bool holds_alternative(const variant<_Types...>& _Var) noexcept {
11801141
// true iff _Var holds alternative _Ty
11811142
constexpr size_t _Idx = _Meta_find_unique_index<variant<_Types...>, _Ty>::value;
1182-
static_assert(_Idx != _Meta_npos, "holds_alternative<T>(const variant<Types...>&) requires T to occur exactly "
1183-
"once in Types. (N4950 [variant.get]/1)");
1184-
return _Var.index() == _Idx;
1143+
if constexpr (_Idx != _Meta_npos) {
1144+
return _Var.index() == _Idx;
1145+
} else {
1146+
static_assert(_Always_false<_Ty>, "holds_alternative<T>(const variant<Types...>&) requires T to occur exactly "
1147+
"once in Types. (N4971 [variant.get]/1)");
1148+
}
11851149
}
11861150

11871151
_EXPORT_STD template <size_t _Idx, class... _Types>
@@ -1229,33 +1193,45 @@ _EXPORT_STD template <class _Ty, class... _Types>
12291193
_NODISCARD constexpr decltype(auto) get(variant<_Types...>& _Var) {
12301194
// access the contained value of _Var if its alternative _Ty is active
12311195
constexpr size_t _Idx = _Meta_find_unique_index<variant<_Types...>, _Ty>::value;
1232-
static_assert(_Idx < sizeof...(_Types),
1233-
"get<T>(variant<Types...>&) requires T to occur exactly once in Types. (N4950 [variant.get]/5)");
1234-
return _STD get<_Idx>(_Var);
1196+
if constexpr (_Idx < sizeof...(_Types)) {
1197+
return _STD get<_Idx>(_Var);
1198+
} else {
1199+
static_assert(_Always_false<_Ty>,
1200+
"get<T>(variant<Types...>&) requires T to occur exactly once in Types. (N4971 [variant.get]/8)");
1201+
}
12351202
}
12361203
_EXPORT_STD template <class _Ty, class... _Types>
12371204
_NODISCARD constexpr decltype(auto) get(variant<_Types...>&& _Var) {
12381205
// access the contained value of _Var if its alternative _Ty is active
12391206
constexpr size_t _Idx = _Meta_find_unique_index<variant<_Types...>, _Ty>::value;
1240-
static_assert(_Idx < sizeof...(_Types),
1241-
"get<T>(variant<Types...>&&) requires T to occur exactly once in Types. (N4950 [variant.get]/5)");
1242-
return _STD get<_Idx>(_STD move(_Var));
1207+
if constexpr (_Idx < sizeof...(_Types)) {
1208+
return _STD get<_Idx>(_STD move(_Var));
1209+
} else {
1210+
static_assert(_Always_false<_Ty>,
1211+
"get<T>(variant<Types...>&&) requires T to occur exactly once in Types. (N4971 [variant.get]/8)");
1212+
}
12431213
}
12441214
_EXPORT_STD template <class _Ty, class... _Types>
12451215
_NODISCARD constexpr decltype(auto) get(const variant<_Types...>& _Var) {
12461216
// access the contained value of _Var if its alternative _Ty is active
12471217
constexpr size_t _Idx = _Meta_find_unique_index<variant<_Types...>, _Ty>::value;
1248-
static_assert(_Idx < sizeof...(_Types),
1249-
"get<T>(const variant<Types...>&) requires T to occur exactly once in Types. (N4950 [variant.get]/5)");
1250-
return _STD get<_Idx>(_Var);
1218+
if constexpr (_Idx < sizeof...(_Types)) {
1219+
return _STD get<_Idx>(_Var);
1220+
} else {
1221+
static_assert(_Always_false<_Ty>,
1222+
"get<T>(const variant<Types...>&) requires T to occur exactly once in Types. (N4971 [variant.get]/8)");
1223+
}
12511224
}
12521225
_EXPORT_STD template <class _Ty, class... _Types>
12531226
_NODISCARD constexpr decltype(auto) get(const variant<_Types...>&& _Var) {
12541227
// access the contained value of _Var if its alternative _Ty is active
12551228
constexpr size_t _Idx = _Meta_find_unique_index<variant<_Types...>, _Ty>::value;
1256-
static_assert(_Idx < sizeof...(_Types),
1257-
"get<T>(const variant<Types...>&&) requires T to occur exactly once in Types. (N4950 [variant.get]/5)");
1258-
return _STD get<_Idx>(_STD move(_Var));
1229+
if constexpr (_Idx < sizeof...(_Types)) {
1230+
return _STD get<_Idx>(_STD move(_Var));
1231+
} else {
1232+
static_assert(_Always_false<_Ty>,
1233+
"get<T>(const variant<Types...>&&) requires T to occur exactly once in Types. (N4971 [variant.get]/8)");
1234+
}
12591235
}
12601236

12611237
_EXPORT_STD template <size_t _Idx, class... _Types>
@@ -1275,17 +1251,23 @@ _EXPORT_STD template <class _Ty, class... _Types>
12751251
_NODISCARD constexpr add_pointer_t<_Ty> get_if(variant<_Types...>* _Ptr) noexcept {
12761252
// get the address of *_Ptr's contained value if it holds alternative _Ty
12771253
constexpr size_t _Idx = _Meta_find_unique_index<variant<_Types...>, _Ty>::value;
1278-
static_assert(_Idx != _Meta_npos,
1279-
"get_if<T>(variant<Types...> *) requires T to occur exactly once in Types. (N4950 [variant.get]/9)");
1280-
return _STD get_if<_Idx>(_Ptr);
1254+
if constexpr (_Idx != _Meta_npos) {
1255+
return _STD get_if<_Idx>(_Ptr);
1256+
} else {
1257+
static_assert(_Always_false<_Ty>,
1258+
"get_if<T>(variant<Types...> *) requires T to occur exactly once in Types. (N4971 [variant.get]/12)");
1259+
}
12811260
}
12821261
_EXPORT_STD template <class _Ty, class... _Types>
12831262
_NODISCARD constexpr add_pointer_t<const _Ty> get_if(const variant<_Types...>* _Ptr) noexcept {
12841263
// get the address of *_Ptr's contained value if it holds alternative _Ty
12851264
constexpr size_t _Idx = _Meta_find_unique_index<variant<_Types...>, _Ty>::value;
1286-
static_assert(_Idx != _Meta_npos,
1287-
"get_if<T>(const variant<Types...> *) requires T to occur exactly once in Types. (N4950 [variant.get]/9)");
1288-
return _STD get_if<_Idx>(_Ptr);
1265+
if constexpr (_Idx != _Meta_npos) {
1266+
return _STD get_if<_Idx>(_Ptr);
1267+
} else {
1268+
static_assert(_Always_false<_Ty>,
1269+
"get_if<T>(const variant<Types...> *) requires T to occur exactly once in Types. (N4971 [variant.get]/12)");
1270+
}
12891271
}
12901272

12911273
template <class _Op, class _Result, class... _Types>

0 commit comments

Comments
 (0)