4085. ranges::generate_random's helper lambda should specify the return type

Section: 26.12.2 [alg.rand.generate] Status: Ready Submitter: Hewill Kang Opened: 2024-04-28 Last modified: 2024-10-09

Priority: 2

View other active issues in [alg.rand.generate].

View all other issues in [alg.rand.generate].

View all issues with Ready status.

Discussion:

The non-specialized case of generate_random(r, g, d) would call ranges::generate(r, [&d, &g] { return invoke(d, g); }). However, the lambda does not explicitly specify the return type, which leads to a hard error when invoke returns a reference to the object that is not copyable or R is not the output_range for decay_t<invoke_result_t<D&, G&>>.

Previous resolution [SUPERSEDED]:

This wording is relative to N4981.

  1. Modify 26.12.2 [alg.rand.generate] as indicated:

    template<class R, class G, class D>
      requires output_range<R, invoke_result_t<D&, G&>> && invocable<D&, G&> &&
               uniform_random_bit_generator<remove_cvref_t<G>>
    constexpr borrowed_iterator_t<R> ranges::generate_random(R&& r, G&& g, D&& d);
    

    -5- Effects:

    1. (5.1) — […]

    2. (5.2) — […]

    3. (5.3) — Otherwise, calls:

      ranges::generate(std::forward<R>(r), [&d, &g] -> decltype(auto) { return invoke(d, g); });
      

    -6- Returns: ranges::end(r)

    -7- Remarks: The effects of generate_random(r, g, d) shall be equivalent to

    ranges::generate(std::forward<R>(r), [&d, &g] -> decltype(auto) { return invoke(d, g); })
    

[2024-05-12, Hewill Kang provides improved wording]

[2024-08-02; Reflector poll]

Set priority to 2 after reflector poll.

[2024-10-09; LWG telecon: Move to Ready]

Proposed resolution:

This wording is relative to N4981.

  1. Modify 29.5.2 [rand.synopsis], header <random> synopsis, as indicated:

    #include <initializer_list>     // see 17.10.2 [initializer.list.syn]
    
    namespace std {
      […]
      namespace ranges {
        […]
        template<class R, class G, class D>
          requires output_range<R, invoke_result_t<D&, G&>> && invocable<D&, G&> &&
                   uniform_random_bit_generator<remove_cvref_t<G>> &&
                   is_arithmetic_v<invoke_result_t<D&, G&>>
        constexpr borrowed_iterator_t<R> generate_random(R&& r, G&& g, D&& d);
    
        template<class G, class D, output_iterator<invoke_result_t<D&, G&>> O, sentinel_for<O> S>
          requires invocable<D&, G&> && uniform_random_bit_generator<remove_cvref_t<G>> &&
                   is_arithmetic_v<invoke_result_t<D&, G&>>
        constexpr O generate_random(O first, S last, G&& g, D&& d);
      }
      […]
    }
    
  2. Modify 26.12.2 [alg.rand.generate] as indicated:

    template<class R, class G, class D>
      requires output_range<R, invoke_result_t<D&, G&>> && invocable<D&, G&> &&
               uniform_random_bit_generator<remove_cvref_t<G>> &&
               is_arithmetic_v<invoke_result_t<D&, G&>>
    constexpr borrowed_iterator_t<R> ranges::generate_random(R&& r, G&& g, D&& d);
    

    -5- Effects:

    […]
    template<class G, class D, output_iterator<invoke_result_t<D&, G&>> O, sentinel_for<O> S>
      requires invocable<D&, G&> && uniform_random_bit_generator<remove_cvref_t<G>> &&
               is_arithmetic_v<invoke_result_t<D&, G&>>
    constexpr O ranges::generate_random(O first, S last, G&& g, D&& d);
    

    -8- Effects: Equivalent to:

    […]