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!
  • [Bug libstdc++/100... gcc-bugs at marehr dot dialup.fu-berlin.de via Gcc-bugs

Reply via email to