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

extract an array from another array at compile time using c++

本文关键字:数组 另一个 提取 C++ 编译      更新时间:2023-10-16

不确定是否有可能用于更高版本的 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
};

如评论中所述,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,但该示例应该给出执行此操作的方法。

要将其移植到 C++11,请执行以下操作:

  • 不要使用 auto 作为返回类型,而是显式指定std::array(简单(

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

如果明确索引而不使用范围是可以的,这里有一个应该在 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 }

我喜欢

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的要求相匹配

这是 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>

填充通过选择元素获得的dataM元素从连续Stride大小间隔开始的偏移Offset 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 1Off 0。帮助程序函数sample_size嵌入约定,如果Stride为 0,则得到一个空样本。

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

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

其中报告:

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,你会在方式像:

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

(g++ 6.1/clang++ 3.8, -std=c++11 -wall -wextra -pedantic(