Retrieve an array from another array at compile time using C ++

Not sure if this is possible for a later version of C ++. (I cannot figure out using traditional C ++ to achieve the following behaviofgr.)

For instance,

If I have an array defined as follows:

In the header file

struct Def { static const int N = 5; static const double data[N]; }; 

In his cpp

 const double Def::data[Def::N] = {0,1,2,3,4}; 

Is it possible to have a get_subarray template such that

get_subarray<Def,2,0>::data will be an array of contents {0,2,4}

get_subarray<Def,2,1>::data will be an array of contents {1,3}

Where

 template<typename T, int M, int m> struct get_phase { // some code for the array variable data which will // extract element from T::data for every M sample offset by index m }; 
+6
source share
3 answers

I like the skypjack solution, but it does not retrieve the requested values. The skypjack version has two parameters: "begin" and "end". The OP requested a "step" or a "frequency" and a "start".

I changed it in accordance with the requested parameters “frequency” and “start”, providing non-peak parameters to the templates with more self-evident names and rewriting a couple of index calculations:

 #include<utility> #include<iostream> #include<array> template <std::size_t Freq, std::size_t Start, typename T, std::size_t Dim, std::size_t... I> constexpr std::array<T, sizeof...(I)> extractHelper (const std::array<T, Dim> & arr, std::integer_sequence<std::size_t, I...>) { return { { std::get<Freq*I+Start>(arr)... } }; } template <std::size_t Freq, std::size_t Start, typename T, std::size_t Dim> constexpr auto extractSamples (const std::array<T, Dim> & arr) { return extractHelper<Freq, Start> (arr, std::make_index_sequence<(Dim+Freq-1-Start)/Freq>()); } 

Here are some test codes:

 int main() { constexpr std::array<int, 8> a1 = { { 0, 1, 2, 3, 4, 5, 6, 7 } }; constexpr auto e1 = extractSamples<2, 0>(a1); constexpr auto e2 = extractSamples<2, 1>(a1); constexpr auto e3 = extractSamples<3, 0>(a1); constexpr auto e4 = extractSamples<3, 1>(a1); constexpr auto e5 = extractSamples<3, 2>(a1); std::cout << "samples<2, 0>: "; for ( auto const & i : e1 ) std::cout << ' ' << i; std::cout << "\nsamples<2, 1>: "; for ( auto const & i : e2 ) std::cout << ' ' << i; std::cout << "\nsamples<3, 0>: "; for ( auto const & i : e3 ) std::cout << ' ' << i; std::cout << "\nsamples<3, 1>: "; for ( auto const & i : e4 ) std::cout << ' ' << i; std::cout << "\nsamples<3, 2>: "; for ( auto const & i : e5 ) std::cout << ' ' << i; std::cout << std::endl; return 0; } 

Output:

 samples<2, 0>: 0 2 4 6 samples<2, 1>: 1 3 5 7 samples<3, 0>: 0 3 6 samples<3, 1>: 1 4 7 samples<3, 2>: 2 5 

which matches OP requests

+1
source

As mentioned in the comments, OP is also interested in C ++ 14 based solutions.
Here is one of them:

 #include<functional> #include<cstddef> #include<utility> #include<array> template<std::size_t O, typename T, std::size_t N, std::size_t... I> constexpr std::array<T, sizeof...(I)> f(const std::array<T, N> &arr, std::index_sequence<I...>) { return { std::get<I+O>(arr)... }; } template<std::size_t B, std::size_t E, typename T, std::size_t N> constexpr auto f(const std::array<T, N> &arr) { return f<B>(arr, std::make_index_sequence<EB>()); } int main() { constexpr std::array<int, 3> a1 = { 0, 1, 2 }; constexpr auto a2 = f<1, 2>(a1); static_assert(a1[1] == a2[0], "!"); } 

In this case, a2 is equal to { 1 } .
It is worth checking B and E to make sure that E larger than B , but the example should give an idea of ​​how to do this.

To port it to C ++ 11:

  • Do not use auto as the return type, but explicitly specify std::array (easy)

  • Find one of the available C ++ 11 integer_sequence and make_index_sequence implementations on the make_index_sequence and use it

If it's good to be explicit about indices and not use a range, here is a naive snippet that should work in C ++ 11:

 #include<cstddef> #include<utility> #include<array> template<std::size_t... I, typename T, std::size_t N> constexpr std::array<T, sizeof...(I)> f(const std::array<T, N> &arr) { return { std::get<I>(arr)... }; } int main() { constexpr std::array<int, 3> a1 = { 0, 1, 2 }; constexpr auto a2 = f<1>(a1); static_assert(a1[1] == a2[0], "!"); } 

As in the previous example, a2 is { 1 } .

+4
source

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)

+1
source

All Articles