xmllmx
xmllmx

Reputation: 42225

Why can't compile std::views::take(std::uint64_t{})?

#include <cstdint>
#include <ranges>

int main()
{
    auto const il = {1, 2, 3, 4, 5, 6};
    auto const n1 = std::int32_t{3};
    auto const n2 = std::uint32_t{3};
    auto const n3 = std::int64_t{3};
    auto const n4 = std::uint64_t{3};

    il | std::views::take(n1); // ok
    il | std::views::take(n2); // ok
    il | std::views::take(n3); // ok
    il | std::views::take(n4); // error
}

See online demo

Why can't compile std::views::take(std::uint64_t{})?

Upvotes: 1

Views: 123

Answers (2)

Barry
Barry

Reputation: 302738

Prior to P2367, the default case of views::take(E, F) was specified to be expression-equivalent to ranges::take_view{E, F}. Note the braces.

ranges::take_view<V> takes a range_difference_t<V> (which is signed) as its second argument. List-initialization rejects narrowing (e.g. attempting to initialize a ptrdiff_t with a uint64_t), so your example was rejected.

However, now views::take(E, F) is specified to be expression-equivalent to ranges::take_view(E, F). With parentheses. Which means no check for narrowing, which means passing a uint64_t is totally fine.

libstdc++ implemented that change on Apr 30 which I guess was too late for gcc 11.1 but that change is there in gcc 11.2, which accepts your code.

Upvotes: 3

Caleth
Caleth

Reputation: 62576

range | std::views::take(n) is expression equivalent to std::ranges::take_view(range, n), which takes a ranges::range_difference_t<V>.

Following the aliases through, gcc 11.1 doesn't want to consider unsigned long as usable where a long is wanted

Upvotes: 1

Related Questions