c++c++20std-rangesc++23

Single-element range


Given a function that accepts a range, for example:

void f(const std::ranges::range auto& r);

Sometimes I have only one element that I want to pass to the function.

There are multiple ways of creating a single-element range for this purpose, for example:

int i{};

/*1*/ f(std::array{i});
/*2*/ f(std::span{&i, 1});
/*3*/ f(std::ranges::views::single(i));

All of those work, but I'd like to know if there are practical differences (efficiency?) between them and if any of them (or a different one) should be preferred.

(The question is tagged with both C++20 and C++23 in case there are differences between the versions that affect the answer)


Solution

  • If you need to store a range adaptor constructed from r, e.g. std::views::concat(r, something):

    1. If r is an lvalue of std::array{i}: Because std::array does not model view, the resulting range adaptor will store a pointer to r.
    2. If r is std::span{&i, 1}: The resulting range adaptor will store a copy of r, which contains a pointer to i.
    3. If r is std::views::single(i): The resulting range adaptor will store a copy of r, which contains a copy of i.

    If r is an rvalue of std::array{i}, the range adaptor will also store a copy (effectively equivalent to std::views::single(i), but with an extra wrapper).

    In general, I'd recommend to use std::view::single(i) because it's least likely to produce dangling pointers, unless the object i is very expensive to copy.