Join the Stack Overflow Community
Stack Overflow is a community of 6.6 million programmers, just like you, helping each other.
Join them; it only takes a minute:
Sign up

Not sure if it's possible for more later version of c++. (I can't figure out using traditional c++ to achieve the following behaviofgr.)

For example,

If I have an array defined like this:

In the header file

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

In its cpp

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

Is it possible to have a template get_subarray such that

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

get_subarray<Def,2,1>::data will be an array of content {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
};
share|improve this question
    
You could try using std::copy into a second array of the correct size. – Elizafox Jul 24 '16 at 20:59
1  
@ElizabethMyers Doesn't happen at compile-time though. – Some programmer dude Jul 24 '16 at 21:01
2  
C++14 makes this easier than C++11 – Yakk Jul 24 '16 at 21:10
    
@Yakk will be really useful to see how both solutions (C++11 vs C++14) to tackle the same problem. – Carson Pun Jul 24 '16 at 21:13
1  
@carson except the c++11 version is painful to write. So I would rather not. – Yakk Jul 24 '16 at 22:02
up vote 1 down vote accepted

I like the skypjack's solution but it doesn't extract the requested values. skypjack's version has two parameters, "begin" and "end". The OP requested "stride" or "frequency" and "begin".

I've modified it to match the OP's requested "frequency" and "start" arguments, giving the template non-type parameters more self-explaining 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 is some test code:

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;
 }

The output is:

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 the OP's requests

share|improve this answer
    
I didn't want to insult you. If you got it as an intention to offend, I apologize. – skypjack Jul 25 '16 at 13:18
    
@skypjack - OK; maybe I'm to much touchy. – max66 Jul 25 '16 at 13:22
    
No problem. Deleted the comment. I'm sorry for the misunderstanding, I didn't want to insult you. – skypjack Jul 25 '16 at 14:11
    
@skypjack - No problem: the misunderstanding was I my failure. I see that you've got the point (from the Yakk's comment) about the difference between your solution and the OP question so I've deleted my comment to. – max66 Jul 25 '16 at 19:22
    
@Yakk - thanks for the editing: write in English is very difficult for me. – max66 Jul 25 '16 at 19:23

As mentioned in the comments, the OP is interested also 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<E-B>());
}

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's worth it checking B and E so as to verify that E is greater than B, but the example should give an idea of what's the way to do it.

To port it to C++11:

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

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

If it's fine to be explicit about the indexes and not use a range, here is a naïve 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 }.

share|improve this answer
    
The OP's get_subarray<Def,2,1> is stride start, not begin end as you wrote. – Yakk Jul 25 '16 at 13:40
    
@Yakk The C++11 solution works as expected indeed. :-) ... That said, easy to update to do that. I'll have a try in the evening, now I'm at work. I'm sorry. – skypjack Jul 25 '16 at 13:44

Here's a solution in C++11 without additives. As usual, compiletime recursion makes do for the lack of C++14's std::index_sequence - in this case by recursively assembling the list of indices that select the desired sample of the data array.

Given some:

constexpr std::array<T,N> data{{...}};

initialized ... with the Ts of your choice, then:

constexpr auto sample = get_sample<Stride,Offset>(data);

will define sample as a compiletime

std::array<T,M>

populated with the M elements of data obtained by selecting the element at offset Offset from the start of successive Stride-sized intervals of data.

#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 helper function sample_size embeds the convention that if Stride is 0 you get an empty sample.

For an illustrative program, you can append:

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 

See it live

If you want to apply this to your class Def, you would redefine it in an amenable way like:

struct Def {
  static constexpr int N = 5;
  static constexpr std::array<double,N> data{{0,1,2,3,4}};
};

and get your compiletime sample like:

constexpr auto s = get_sample<2,1>(Def::data);

(g++ 6.1/clang++ 3.8, -std=c++11 -Wall -Wextra -pedantic)

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.