std::ranges::elements_of(3)

πŸ“¦
version 2024.07.05 Β· 3 versions
, in nixpkgs unstable, opensuse-leap 16.0

✨ std::ranges::elements_of ✨

okay bestie, welcome to the std::ranges::elements_of page from the C++ Standard Libary (yes that's how the header spells it, don't come for me πŸ’…). this one's short and sweet and honestly kind of iconic once you get what it's for, so let's go 🫢


🌸 NAME 🌸

std::ranges::elements_of β€” literally just std::ranges::elements_of, that's the whole name, no cap


πŸ¦‹ Synopsis πŸ¦‹

bestie it lives in <ranges>, obviously:

Defined in header <ranges>
template< ranges::range R, class Allocator =
std::allocator<std::byte> >
(since C++23)
   struct elements_of;

so what does it actually do? it encapsulates a range. Specializations of elements_of act as a tag in overload sets to disambiguate when a range should be treated as a sequence rather than as a single value. that's the whole vibe check: "hey compiler, this range? i mean the stuff inside it, not the range itself as one thing." periodt ✨


πŸ‘‘ Template parameters πŸ‘‘

  • R β€” a type that satisfies range πŸ’–
  • Allocator β€” an allocator type that meets the requirements of Allocator πŸŽ€

πŸ“ Data members πŸ“

two of them, both public, both living their best life:

  • range β€” a range of type R (public member object) 🌈
  • allocator β€” an allocator of type Allocator, and it has a default member initializer that value initializes itself (public member object) ⭐
All these members are declared with the [[no_unique_address]] attribute. yes, both of them. the compiler is being thrifty and we respect it πŸ™ˆ

🧚 Deduction guide 🧚

(since C++23) β€” here it is, character for character:

template< class R, class Allocator = std::allocator<std::byte> >
elements_of( R&&, Allocator = Allocator() ) -> elements_of<R&&,
Allocator>;

so you can just write std::ranges::elements_of(r) and the R&& gets deduced for you. slay πŸ’…


πŸ”₯ Example πŸ”₯

// Run this code β€” go on, run it, i'll wait 🫢

#include <any>
#include <generator>
#include <iostream>
#include <ranges>
#include <string_view>

template<bool Elementwise>
std::generator<std::any> gen(std::ranges::input_range auto&& r)
{
    if constexpr (Elementwise)
        co_yield std::ranges::elements_of(r); // yield each element of
r
    else
        co_yield r;                           // yield r as a single
value
}

int main()
{
    auto test = std::string_view{"test"};

    for (std::any a : gen<true>(test))
        std::cout << '[' << std::any_cast<char>(a) << "] ";
    std::cout << '\n';

    for (std::any a : gen<false>(test))
        std::cout << '[' << std::any_cast<std::string_view>(a) << "] ";
    std::cout << '\n';
}

Output:

[t] [e] [s] [t]
[test]

see what happened there?? with gen<true> the elements_of tag made it yield each character one by one β€” [t] [e] [s] [t] β€” and with gen<false> it just yielded the whole string_view as one single value β€” [test]. that's literally the entire point of the tag, demonstrated in four lines. ate. πŸ”₯


πŸ’œ References πŸ’œ

  • C++23 standard (ISO/IEC 14882:2023):
  • 26.5.6 Class template elements_of [range.elementsof]

and that's the page!! πŸ’– cute little struct, huge disambiguation energy. this was brought to you by http://cppreference.com, dated 2024.06.10, and the page itself is std::ranges::elements_of(3) β€” go forth and yield your ranges correctly bestie, ily πŸŒΈπŸ¦‹πŸŽ€βœ¨

πŸ“¦ where this page comes from