Here's a solution in C ++ 11 with no additives. As usual, compiletime Replication does this because of the lack of C ++ 14 std::index_sequence - in this case, by recursively std::index_sequence list of indexes that select the desired data array sample.
For some:
constexpr std::array<T,N> data{{...}};
initialized ... using T of your choice, then:
constexpr auto sample = get_sample<Stride,Offset>(data);
define sample as compilation
std::array<T,M>
filled with M data elements obtained by selecting an element with Offset offset from the beginning of successive Stride data intervals.
#include <array> #include <type_traits> constexpr std::size_t sample_size(std::size_t size, std::size_t stride, std::size_t off) { return stride == 0 ? 0 : ((size - off) / stride) + (off + (((size - off) / stride) * stride) < size); } template< std::size_t Stride = 1, std::size_t Off = 0, typename T, std::size_t Size, std::size_t ...Is > constexpr typename std::enable_if< sizeof ...(Is) == sample_size(Size,Stride,Off), std::array<T, sample_size(Size,Stride,Off)> >::type get_sample(std::array<T,Size> const & data) { return std::array<T,sample_size(Size,Stride,Off)>{{data[Is]... }}; } template< std::size_t Stride = 1, std::size_t Off = 0, typename T, std::size_t Size, std::size_t ...Is > constexpr typename std::enable_if< sizeof ...(Is) != sample_size(Size,Stride,Off), std::array<T, sample_size(Size,Stride,Off)> >::type get_sample(std::array<T,Size> const & data) { return get_sample<Stride,Off,T,Size,Is...,(sizeof...(Is) * Stride) + Off> (data); }
By default, Stride is 1 , and Off is 0 . The sample_size helper function concludes that if Stride is 0, you get an empty sample.
For an illustrative program, you can add:
constexpr std::array<int,5> data1{{0,1,2,3,4}}; constexpr auto sample1 = get_sample(data1); constexpr auto sample2 = get_sample<2>(data1); constexpr auto sample3 = get_sample<2,1>(data1); constexpr auto sample4 = get_sample<6>(data1); constexpr auto sample5 = get_sample<6,5>(data1); static_assert(sample5.size() == 0,""); constexpr std::array<float,6> data2{{1.1,2.2,3.3,4.4,5.5,6.6}}; constexpr auto sample6 = get_sample<2>(data2); constexpr auto sample7 = get_sample<2,3>(data2); constexpr auto sample8 = get_sample<3,2>(data2); constexpr std::array<int,0> data3{}; constexpr auto sample9 = get_sample<0>(data3); static_assert(sample9.size() == 0,""); constexpr auto sample10 = get_sample<2>(data3); static_assert(sample10.size() == 0,""); #include <iostream> int main() { std::cout << "get_sample<> of {0,1,2,3,4}\n"; for (auto const & e : sample1) { std::cout << e << ' '; } std::cout << '\n'; std::cout << "get_sample<2> of {0,1,2,3,4}\n"; for (auto const & e : sample2) { std::cout << e << ' '; } std::cout << '\n'; std::cout << "get_sample<2,1> of {0,1,2,3,4}\n"; for (auto const & e : sample3) { std::cout << e << ' '; } std::cout << '\n'; std::cout << "get_sample<6> of {0,1,2,3,4}\n"; for (auto const & e : sample4) { std::cout << e << ' '; } std::cout << '\n'; std::cout << "get_sample<2> of {{1.1,2.2,3.3,4.4,5.5,6.6}}\n"; for (auto const & e : sample6) { std::cout << e << ' '; } std::cout << '\n'; std::cout << "get_sample<2,3> of {{1.1,2.2,3.3,4.4,5.5,6.6}}\n"; for (auto const & e : sample7) { std::cout << e << ' '; } std::cout << '\n'; std::cout << "get_sample<3,2> of {{1.1,2.2,3.3,4.4,5.5,6.6}}\n"; for (auto const & e : sample8) { std::cout << e << ' '; } std::cout << '\n'; return 0; }
which reports:
get_sample<> of {0,1,2,3,4} 0 1 2 3 4 get_sample<2> of {0,1,2,3,4} 0 2 4 get_sample<2,1> of {0,1,2,3,4} 1 3 get_sample<6> of {0,1,2,3,4} 0 get_sample<2> of {1.1,2.2,3.3,4.4,5.5,6.6} 1.1 3.3 5.5 get_sample<2,3> of {1.1,2.2,3.3,4.4,5.5,6.6} 4.4 6.6 get_sample<3,2> of {1.1,2.2,3.3,4.4,5.5,6.6} 3.3 6.6
Watch live
If you want to apply this to your Def class, you would redefine it in a suitable one as:
struct Def { static constexpr int N = 5; static constexpr std::array<double,N> data{{0,1,2,3,4}}; };
and get your sample to compile:
constexpr auto s = get_sample<2,1>(Def::data);
(g ++ 6.1 / clang ++ 3.8, -std = C ++ 11 -Wall -Wextra -pedantic)