Bug 106669 - incorrect definition of viewable_range ("more madness with move-only views")
Summary: incorrect definition of viewable_range ("more madness with move-only views")
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 12.1.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
Depends on:
Reported: 2022-08-17 17:39 UTC by Hannes Hauswedell
Modified: 2022-08-24 14:29 UTC (History)
2 users (show)

See Also:
Known to work:
Known to fail:
Last reconfirmed:


Note You need to log in before you can comment on or make changes to this bug.
Description Hannes Hauswedell 2022-08-17 17:39:19 UTC
In GCC12.1 we now have ranges that are views, but whose references aren't viewable. See the code below.

Before views were allowed to be move-only, S was not considered a view, but `S &` was considered viewable (it would just be wrapped in ref_view). Now, S is a valid view, and S (no-ref!) is also a viewable range. But apparently the requirements for viewable_range were not correctly updated, because `S &` is now no longer viewable. The code in the standard is the following:

template<class T>
  concept viewable_­range =
    range<T> &&
    ((view<remove_cvref_t<T>> && constructible_­from<remove_cvref_t<T>, T>) ||
     (!view<remove_cvref_t<T>> &&
      (is_lvalue_reference_v<T> || (movable<remove_reference_t<T>> && !is-initializer-list<T>))));

For any `T &` where T is a view but not copy-constructible, this concept will evaluate to false. I am assuming this is an LWG issue and will report on the reflector unless you see a good reason for the current behaviour?

#include <string_view>
#include <ranges>

struct S : std::string_view, std::ranges::view_base
    S() = delete;
    S(S const &) = delete;
    S(S &&) = default;
    S & operator=(S const &) = delete;
    S & operator=(S &&) = default;

    S(std::string_view v) : std::string_view{v} {}

static_assert(std::ranges::view<S>);             // fails expectedly on gcc11.3, passes on gcc12.1
static_assert(std::ranges::viewable_range<S>);   // fails expectedly on gcc11.3, passes on gcc12.1
static_assert(std::ranges::viewable_range<S &>); // passes on gcc11.3, fails unexpectedly on gcc12.1

int main()
    S s{"foo"};
    s | std::views::filter([] (char) { return true;}); // this fails in gcc12.1
Comment 1 Hannes Hauswedell 2022-08-18 11:40:30 UTC
This affects GCC 10.4 and GCC 11.3 since move-only views were backported.

The following part of the draft standard also needs changing:



decay-copy(E) if that expression is well-formed and the decayed type of E models view.

This will make references to move-only views pick the second option (ref_view).
Comment 2 Jonathan Wakely 2022-08-23 15:48:31 UTC
Please open an LWG issue.
Comment 3 Hannes Hauswedell 2022-08-24 14:29:56 UTC
According to LWG, this "works as intended". I will try to prepare some more arguments for changing this, but in any case it is not a GCC issue –– yet ;-)