Slicing std::array

13,652

Solution 1

The constructors for std::array are implicitly defined so you can't initialize it with a another container or a range from iterators. The closest you can get is to create a helper function that takes care of the copying during construction. This allows for single phase initialization which is what I believe you're trying to achieve.

template<class X, class Y>
X CopyArray(const Y& src, const size_t size)
{
    X dst;
    std::copy(src.begin(), src.begin() + size, dst.begin());
    return dst;
}
std::array<int, 5> arr5 = CopyArray<decltype(arr5)>(arr10, 5);

You can also use something like std::copy or iterate through the copy yourself.

std::copy(arr10.begin(), arr10.begin() + 5, arr5.begin());

Solution 2

Sure. Wrote this:

template<int...> struct seq {};
template<typename seq> struct seq_len;
template<int s0,int...s>
struct seq_len<seq<s0,s...>>:
    std::integral_constant<std::size_t,seq_len<seq<s...>>::value> {};
template<>
struct seq_len<seq<>>:std::integral_constant<std::size_t,0> {};
template<int Min, int Max, int... s>
struct make_seq: make_seq<Min, Max-1, Max-1, s...> {};
template<int Min, int... s>
struct make_seq<Min, Min, s...> {
  typedef seq<s...> type;
};
template<int Max, int Min=0>
using MakeSeq = typename make_seq<Min,Max>::type;

template<std::size_t src, typename T, int... indexes>
std::array<T, sizeof...(indexes)> get_elements( seq<indexes...>, std::array<T, src > const& inp ) {
  return { inp[indexes]...  };
}
template<int len, typename T, std::size_t src>
auto first_elements( std::array<T, src > const& inp )
  -> decltype( get_elements( MakeSeq<len>{}, inp ) )
{
  return get_elements( MakeSeq<len>{}, inp  );
}

Where the compile time indexes... does the remapping, and MakeSeq makes a seq from 0 to n-1.

Live example.

This supports both an arbitrary set of indexes (via get_elements) and the first n (via first_elements).

Use:

std::array< int, 10 > arr = {0,1,2,3,4,5,6,7,8,9};
std::array< int, 6 > slice = get_elements(arr, seq<2,0,7,3,1,0>() );
std::array< int, 5 > start = first_elements<5>(arr);

which avoids all loops, either explicit or implicit.

Share:
13,652

Related videos on Youtube

sashkello
Author by

sashkello

Laß die Zeit an dir ablaufen wie Wasser

Updated on June 04, 2022

Comments

  • sashkello
    sashkello almost 2 years

    Is there an easy way to get a slice of an array in C++?

    I.e., I've got

    array<double, 10> arr10;
    

    and want to get array consisting of five first elements of arr10:

    array<double, 5> arr5 = arr10.???
    

    (other than populating it by iterating through first array)

    • Luc Danton
      Luc Danton
      A pair of iterators is the closest C++ has to a slice. Something like Boost.Range does allow you to pack them together into one slice-like object, too.