使用c ++在编译时从另一个数组中提取数组

时间:2016-07-24 20:56:55

标签: c++ arrays templates c++11 c++14

不确定是否可以使用更高版本的c ++。 (我无法弄清楚使用传统的c ++来实现以下行为。)

例如,

如果我有一个像这样定义的数组:

在头文件中

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

在其cpp中

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

是否可以使用模板get_subarray

get_subarray<Def,2,0>::data将是一系列内容{0,2,4}

get_subarray<Def,2,1>::data将是一系列内容{1,3}

,其中

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

3 个答案:

答案 0 :(得分:4)

正如评论中所提到的,OP也对基于C ++ 14的解决方案感兴趣 这是其中之一:

#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], "!");
}

在这种情况下,a2等于{ 1 } 值得检查BE以验证E是否大于B,但该示例应该知道执行此操作的方式。< / p>

将其移植到C ++ 11:

  • 不要将auto用作返回类型,而是明确指定std::array(简单)

  • 在网上搜索integer_sequencemake_index_sequence的可用C ++ 11实现之一并使用它

如果可以明确指出索引并且不使用范围,那么这是一个应该在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], "!");
}

与上一个示例一样,a2{ 1 }

答案 1 :(得分:1)

我喜欢skypjack的解决方案,但它不会提取请求的值。 skypjack的版本有两个参数,“开始”和“结束”。 OP要求“跨步”或“频率”和“开始”。

我修改它以匹配OP请求的“频率”和“开始”参数,为模板非类型参数提供更多自解释名称,并重写几个索引计算:

#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>()); }

以下是一些测试代码:

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

输出结果为:

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

匹配OP的请求

答案 2 :(得分:1)

这是C ++ 11中没有添加剂的解决方案。照常, 编译时递归使得缺少C ++ 14 std::index_sequence - 在这种情况下,通过递归组装索引列表 选择所需的数据数组样本。

鉴于一些:

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

使用您选择的...初始化T,然后:

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

sample定义为编译时

std::array<T,M>

填充了通过选择元素获得的M data元素 在距离Offset的连续Stride间隔开始的偏移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); }

Stride

默认情况下,1Off0sample_size。辅助函数Stride 嵌入惯例,如果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; } 为0,则会得到一个空样本。

对于说明性程序,您可以附加:

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 

报道:

Def

See it live

如果您想将其应用于您的班级struct Def { static constexpr int N = 5; static constexpr std::array<double,N> data{{0,1,2,3,4}}; }; ,您可以在适当的时候重新定义它 像:

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

并获取您的编译时样本:

function ask_name(){
     return "What is your name?\n\n";   
     $_SESSION['status'] = "name";
}

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