https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100233
Bug ID: 100233 Summary: [10/11/12] std::views::elements only accepts types that are defined on std::get Product: gcc Version: 10.3.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: libstdc++ Assignee: unassigned at gcc dot gnu.org Reporter: gcc-bugs at marehr dot dialup.fu-berlin.de Target Milestone: --- Hi gcc-team, the following code will not work on custom tuples that don't add a get overload within the std namespace. These tuples work in structured bindings, but not within std::views::elements. ```cpp #include <utility> #include <vector> namespace my_namespace { template <typename ...types> struct S { int x{}; }; } // namespace my_namespace namespace std { template <template <typename ...> typename t, typename ...types> requires std::is_base_of_v<my_namespace::S<types...>, t<types...>> struct tuple_size<t<types...>> : public std::integral_constant<std::size_t, sizeof...(types)> {}; template <std::size_t i, template <typename ...> typename t, typename ...types> requires (i < sizeof...(types)) && std::is_base_of_v<my_namespace::S<types...>, t<types...>> struct tuple_element<i, t<types...>> { using type = int; }; } // namespace std namespace my_namespace { template <std::size_t i, typename ...types> int & get(my_namespace::S<types...> & e) noexcept { return e.x; } } // my_namespace #if !DO_FAIL namespace std { using my_namespace::get; } // namespace std #endif #include <ranges> int main() { // does work with / without defining get within std using tripplet_t = my_namespace::S<int, unsigned, char>; tripplet_t tuple{}; auto & [a, b, c] = tuple; // only works when defining within std std::vector<tripplet_t> vec(10); // std::views::elements<0>(vec); using elements_view_t = std::ranges::elements_view<std::views::all_t<decltype(vec) &>, 0>; } ``` https://godbolt.org/z/n315fednc ``` > g++-10 --std=c++2a -DDO_FAIL=1 <source>:56:93: error: template constraint failure for 'template<class _Vp, long unsigned int _Nm> requires (input_range<_Vp>) && ((view<_Vp>) && (__has_tuple_element<typename std::__detail::__iter_traits_impl<typename std::remove_cv<typename std::remove_reference<decltype(std::__detail::__ranges_begin((declval<_Container&>)()))>::type>::type, std::indirectly_readable_traits<typename std::remove_cv<typename std::remove_reference<decltype(std::__detail::__ranges_begin((declval<_Container&>)()))>::type>::type> >::__iter_traits<typename std::remove_cv<typename std::remove_reference<decltype(std::__detail::__ranges_begin((declval<_Container&>)()))>::type>::type, std::indirectly_readable_traits<typename std::remove_cv<typename std::remove_reference<decltype(std::__detail::__ranges_begin((declval<_Container&>)()))>::type>::type> >::value_type, _Nm>) && (__has_tuple_element<typename std::remove_reference<decltype(*(declval<decltype(std::__detail::__ranges_begin((declval<_Container&>)()))&>)())>::type, _Nm>) && (__returnable_element<decltype(*(declval<decltype(std::__detail::__ranges_begin((declval<_Container&>)()))&>)()), _Nm>)) class std::ranges::elements_view' 56 | using elements_view_t = std::ranges::elements_view<std::views::all_t<decltype(vec) &>, 0>; | ^ <source>:56:93: note: constraints not satisfied In file included from <source>:44: /opt/compiler-explorer/gcc-trunk-20210423/include/c++/12.0.0/ranges: In substitution of 'template<class _Vp, long unsigned int _Nm> requires (input_range<_Vp>) && ((view<_Vp>) && (__has_tuple_element<typename std::__detail::__iter_traits_impl<typename std::remove_cv<typename std::remove_reference<decltype(std::__detail::__ranges_begin((declval<_Container&>)()))>::type>::type, std::indirectly_readable_traits<typename std::remove_cv<typename std::remove_reference<decltype(std::__detail::__ranges_begin((declval<_Container&>)()))>::type>::type> >::__iter_traits<typename std::remove_cv<typename std::remove_reference<decltype(std::__detail::__ranges_begin((declval<_Container&>)()))>::type>::type, std::indirectly_readable_traits<typename std::remove_cv<typename std::remove_reference<decltype(std::__detail::__ranges_begin((declval<_Container&>)()))>::type>::type> >::value_type, _Nm>) && (__has_tuple_element<typename std::remove_reference<decltype(*(declval<decltype(std::__detail::__ranges_begin((declval<_Container&>)()))&>)())>::type, _Nm>) && (__returnable_element<decltype(*(declval<decltype(std::__detail::__ranges_begin((declval<_Container&>)()))&>)()), _Nm>)) class std::ranges::elements_view [with _Vp = std::ranges::ref_view<std::vector<my_namespace::S<int, unsigned int, char> > >; long unsigned int _Nm = 0]': <source>:56:93: required from here /opt/compiler-explorer/gcc-trunk-20210423/include/c++/12.0.0/ranges:3306:13: required for the satisfaction of '__has_tuple_element<std::ranges::range_value_t<_Vp>, _Nm>' [with _Vp = std::ranges::ref_view<std::vector<my_namespace::S<int, unsigned int, char>, std::allocator<my_namespace::S<int, unsigned int, char> > > >; _Nm = 0] /opt/compiler-explorer/gcc-trunk-20210423/include/c++/12.0.0/ranges:3306:35: in requirements with '_Tp __t' [with _Nm = 0; _Tp = my_namespace::S<int, unsigned int, char>] /opt/compiler-explorer/gcc-trunk-20210423/include/c++/12.0.0/ranges:3311:24: note: the required expression 'get<_Nm>(__t)' is invalid 3311 | { std::get<_Nm>(__t) } | ~~~~~~~~~~~~~^~~~~ ``` The standard defines the `get-element` call as ```cpp if constexpr (is_reference_v<range_reference_t<Base>>) { return get<N>(*i); } else { using E = remove_cv_t<tuple_element_t<N, range_reference_t<Base>>>; return static_cast<E>(get<N>(*i)); } ``` https://eel.is/c++draft/range.elements#iterator-3 With some good-will you could say that `get` should be called unqualified :) I know that it isn't stated explicitly, but with how the whole ADL thing with range adaptors work, it is unexpected that it does not work here too. Thank you!