std::ranges::generate_n(3)

πŸ“¦ version 2024.07.05, in nixpkgs unstable, opensuse-leap 16.0

πŸ’… std::ranges::generate_n β€” C++ Standard Library ✨

okay so bestie, welcome to std::ranges::generate_n from the C++ Standard Library β€” this is the glow-up of the classic generate_n, and it's literally so good. girlies, let's get into it 🫢


✨ NAME ✨

std::ranges::generate_n β€” like, exactly std::ranges::generate_n. that's the whole name, no notes πŸ‘‘


🌸 SYNOPSIS 🌸

Defined in header <algorithm>

Call signature (this is the moment, ok, don't panic):

template< std::input_or_output_iterator O, std::copy_constructible F >
requires std::invocable<F&> && std::indirectly_writable<O, std::invoke_result_t<F&>>
constexpr O
    generate_n( O first, std::iter_difference_t<O> n, F gen );

(since C++20) β€” yeah she's a modern girlie πŸ’…

So what does she do? She assigns the result of successive invocations of the function object gen to each element in the range [first, first + n), if 0 < n. Otherwise? Does literally nothing. napping. not her problem 😴


πŸ¦‹ niebloids β€” the vibe check πŸ¦‹

The function-like entities described on this page are niebloids, that is:

  • Explicit template argument lists cannot be specified when calling any of them.
  • None of them are visible to argument-dependent lookup.
  • When any of them are found by normal unqualified lookup as the name to the left of the function-call operator, argument-dependent lookup is inhibited.

In practice, they may be implemented as function objects, or with special compiler extensions. (iykyk 😭)


πŸ’– PARAMETERS πŸ’–

  • first β€” the beginning of the range of elements to modify. like, where the makeover starts πŸ’„
  • n β€” number of elements to modify. how many of them get the treatment, fr fr.
  • gen β€” the generator function object. she's the one doing the actual work, main character energy ✨

πŸŽ€ RETURN VALUE πŸŽ€

Iterator one past the last element assigned if 0 < count β€” otherwise first. so if you asked for zero elements, you just get your own first back, no harm no foul πŸ™ˆ


🌈 COMPLEXITY 🌈

Exactly n invocations of gen() and assignments. not n-1, not n+1 β€” exactly n. slay, precise queen ⭐


πŸ‘‘ POSSIBLE IMPLEMENTATION πŸ‘‘

here's how the girlies at the standards committee probably pictured it:

struct generate_n_fn
{
    template<std::input_or_output_iterator O, std::copy_constructible F>
    requires std::invocable<F&> && std::indirectly_writable<O, std::invoke_result_t<F&>>
    constexpr O operator()(O first, std::iter_difference_t<O> n, F gen) const
    {
        for (; n-- > 0; *first = std::invoke(gen), ++first)
        {}
        return first;
    }
};

inline constexpr generate_n_fn generate_n {};

look at that for loop. that comma operator. that's art, bestie πŸ–ΌοΈπŸ’€


πŸ”₯ EXAMPLE πŸ”₯

// Run this code β€” literally, go run it:

#include <algorithm>
#include <array>
#include <iostream>
#include <random>
#include <string_view>

auto dice()
{
    static std::uniform_int_distribution<int> distr {1, 6};
    static std::random_device engine;
    static std::mt19937 noise {engine()};
    return distr(noise);
}

void print(const auto& v, std::string_view comment)
{
    for (int i : v)
        std::cout << i << ' ';
    std::cout << '(' << comment << ")\n";
}

int main()
{
    std::array<int, 8> v;

    std::ranges::generate_n(v.begin(), v.size(), dice);
    print(v, "dice");

    std::ranges::generate_n(v.begin(), v.size(), [n {0}] mutable { return n++; });
    // same effect as std::iota(v.begin(), v.end(), 0);
    print(v, "iota");
}

🌸 Possible output 🌸

5 5 2 2 6 6 3 5 (dice)
0 1 2 3 4 5 6 7 (iota)

(your dice rolls will differ, that's the whole point of std::random_device, don't come for me 🎲)


πŸ’œ SEE ALSO πŸ’œ

  • ranges::generate (C++20) β€” saves the result of a function in a range (niebloid)
  • ranges::generate_random (C++26) β€” fills a range with random numbers from a uniform random bit generator (niebloid)
  • ranges::fill (C++20) β€” assigns a range of elements a certain value (niebloid)
  • ranges::fill_n (C++20) β€” assigns a value to a number of elements (niebloid)
  • ranges::transform (C++20) β€” applies a function to a range of elements (niebloid)
  • generate_n β€” assigns the results of successive function calls to N elements in a range (function template)

okay that's the whole page bestie, you ate that πŸ’…βœ¨

source: http://cppreference.com β€” version/date: 2024.06.10 β€” page: std::ranges::generate_n(3) πŸ¦‹ mwah, go compile something iconic πŸŒˆπŸ’–

πŸ“¦ where this page comes from