Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Range view to std::vector

Tags:

c++

range

vector

In the proposed C++20 (The One) Ranges TS, what is the proposed method for converting the view into a std::vector?

The following code does not compile:

int                                           
main() {                                                        
    std::vector<float> values = {1.0, 2.0, 3.0, 4.0, 5.2, 6.0, 7.0, 8.0, 9.0}; 
    //fmt::print("{}\n", std::experimental::ranges::views::filter(values, [] (float v) { return v < 5.f; })); 
    std::vector<float> foo = vw::filter(values, [] (float v) { return v < 5.f; }); 
    fmt::print("{}\n", foo);                
}

with the error

../src/view.cpp:19:40: error: conversion from     ‘std::experimental::ranges::v1::filter_view<std::experimental::ranges::v1::ref_view<std::vector<float> >, main()::<lambda(float)> >’ to non-scalar type ‘std::vector<float>’ requested
     std::vector<float> foo = vw::filter(values, [] (float v) { return v < 5.f; }); 

(the commented line will also not compile due to some CV constraints).

So how do I do anything with a view except for using a range-based for loop?

Also some bonus questions:

  1. Is the cmcstl2 implementation I used even following the proposal? The ranges-v3 seems not to be.
  2. Is there any documentation on the Ranges TS? The proposal PDF I found is pretty much an awfully formatted code dump in diff style. In fact directly reading the cmcstl2 sources was way easier to read for me. The cppreference seems to be lacking as well...
like image 743
Richard Vock Avatar asked Nov 11 '19 20:11

Richard Vock


People also ask

How do you access a specific element of a vector?

Vector elements are accessed using indexing vectors, which can be numeric, character or logical vectors. You can access an individual element of a vector by its position (or "index"), indicated using square brackets. In R, the first element has an index of 1. To get the 7th element of the colors vector: colors[7] .

Is std::vector slower than array?

A std::vector can never be faster than an array, as it has (a pointer to the first element of) an array as one of its data members. But the difference in run-time speed is slim and absent in any non-trivial program. One reason for this myth to persist, are examples that compare raw arrays with mis-used std::vectors.

How do you assign a vector to an array?

The syntax for assigning values from an array or list: vectorname. assign(arr, arr + size) Parameters: arr - the array which is to be assigned to a vector size - number of elements from the beginning which has to be assigned.

What is the difference between std::vector and vector?

Difference between std::vector and std::array in C++Vector is a sequential container to store elements and not index based. Array stores a fixed-size sequential collection of elements of the same type and it is index based. Vector is dynamic in nature so, size increases with insertion of elements.


1 Answers

The C++20 method to convert a view to a std::vector (or indeed any other container) is to pass the range's begin and end members to the vector constructor that accepts 2 iterators (and an optional allocator).

I was also looking for an answer to this question. What I really wanted is an overload of the constructor of std::vector accepting a range. Approximately:

template <std::ranges::input_range R>
vector(R&& r) : vector(r.begin(), r.end()) {
}

but that isn't in C++20.

First, I implemented this:

namespace rng = std::ranges;

template <rng::range R>
constexpr auto to_vector(R&& r) {
    using elem_t = std::decay_t<rng::range_value_t<R>>;
    return std::vector<elem_t>{r.begin(), r.end()};
}

which works, but isn't very "rangy": https://godbolt.org/z/f2xAcd

I then did it a bit better:

namespace detail {
    // Type acts as a tag to find the correct operator| overload
    template <typename C>
    struct to_helper {
    };
    
    // This actually does the work
    template <typename Container, rng::range R>
    requires std::convertible_to<rng::range_value_t<R>, typename Container::value_type>
    Container operator|(R&& r, to_helper<Container>) {
        return Container{r.begin(), r.end()};
    }
}

// Couldn't find an concept for container, however a
// container is a range, but not a view.
template <rng::range Container>
requires (!rng::view<Container>)
auto to() {
    return detail::to_helper<Container>{};
}

https://godbolt.org/z/G8cEGqeq6

No doubt one can do better for sized_ranges and containers like std::vector that have a reserve member function.

There is a proposal to add a to function to C++23 (https://wg21.link/p1206) which will do a better job than this, I'm sure.

like image 149
Rupert Nash Avatar answered Oct 13 '22 07:10

Rupert Nash