4

From a RepeatedField which is defined to have exactly N elements, I am filling up an std::array.

std::array<int, 6> entry;
size_t i = 0;
for (const auto& item: msg.items()){
  assert(i < 6);
  entry[i++] = item;
}

This works fine, but is there a better way to initialize it? filling up std::vector works fine with initialization lists, but std::array is really different.

Is it possible to use RepeatedFields in aggregate initialization of structs contaning std::array ?

What I tried so far does not even compile:

entry = {msg.items().begin(), msg.items().end()};

Which is understandable, because std::array doesn't have a constructor accepting an std::initializer_list; But is what I am trying to do even possible?

Dávid Tóth
  • 2,788
  • 1
  • 21
  • 46

4 Answers4

5

You can try use STL algorithms

std::array<int, 6> entry;
assert(msg.items_size() == std::size(entry));
std::copy(std::begin(msg.items()), std::end(msg.items()), begin(entry));

Or if you have multiple cases like this, you can write helper function.

template<typename T, size_t N, typename R, size_t...I>
std::array<T, N> range_to_array_impl(R&& r, std::index_sequence<I...>)
{
    return { r[I]... };
}

template<typename T, size_t N, typename R>
std::array<T, N> range_to_array(R&& r)
{
    assert(std::size(r) == N);
    return range_to_array_impl<T, N>(std::forward<R>(r), std::make_index_sequence<N>{});
}

// use:
auto entry = range_to_array<int, 6>(msg.items());

https://godbolt.org/z/zEjorr7Tx

Marek R
  • 32,568
  • 6
  • 55
  • 140
2

the most simple way is use aggregate initialization directly

assert(items.size() >= 6)
std::array entry = {
   items[0],items[1],items[2],
   items[3],items[4],items[5],
};

or you can write a function to help you

template<std::size_t N, typename C>
auto get_array(C&& c){
    assert(c.size() >= N); // or ==, depend on the need
    return [&]<std::size_t ...Index>(std::index_sequence<Index...>){
        return std::array{c[Index]...};
    }(std::make_index_sequence<N>{});
}

void foo()
{
    std::array entry = get_array<6>(items);
}
Benjamin Buch
  • 4,752
  • 7
  • 28
  • 51
apple apple
  • 10,292
  • 2
  • 16
  • 36
-1

Here is a generalized version that works for arbitrary type like int, double etc. This uses a function template make_array that loops through the elements and populate the elements. The program uses vector and its begin and end methods.

#include <cstdio>
#include <vector>
#include <array>
#include <iostream>
template<typename T, std::size_t N> std::array<T, N> constexpr make_array(const std::vector<T> &repeatedField)
{
    std::array<T, N> tempArray{};                          //local array that will be returned by value
    auto start = repeatedField.begin();                    //iterator to beginning of vector
    std::size_t pos = 0;                                   //to keep track of position 
    while(pos < N && start!=repeatedField.end())          //loop through the elements of the vector or repeatedfield
    {
        tempArray[pos] = *start;
        ++pos;                                  //update pos 
        start++;                                //update iterator
    }
    return tempArray;
}
int main()
{
    std::vector<int> testingVector{1,2,5,8};
    //--------------------------V-------->number of elements  
    auto arr  = make_array<int, 6>(testingVector);

    
    //lets confirm if all objects have the expected value 
    for(const auto &elem: arr)
    {
        std::cout << elem << std::endl; 
    }
    
}

working demo


It is trivial to change the signature of the function template to

template<typename T, std::size_t N> std::array<T, N> constexpr make_array( std::vector<T>::iterator begin, std::vector<T>::iterator end)

and then pass the range when using/calling it.

Jason
  • 36,170
  • 5
  • 26
  • 60
-2

As far as initialization is concerned, this template should do:

template<typename e, std::size_t n, typename r>
constexpr array<e,n> init_array(r&& x)->std::array<e,n>{
    assert((n<=size(r)));
    return [&]<std::size_t ...i>(std::index_sequence<i...>){ return {x[i]...};} (make_index_sequence<n>{});
};

auto entry=create_array<int,6>(msg.items());
Red.Wave
  • 2,790
  • 11
  • 17