gpt4 book ai didi

c++11 constexpr 将 std::array 列表展平为数组

转载 作者:IT老高 更新时间:2023-10-28 21:55:14 26 4
gpt4 key购买 nike

我从 c++11 开始,constexpr 和模板元编程似乎是在微型微 Controller 上节省稀缺内存的好方法。

有没有办法写一个模板来展平一个 constexpr 数组列表,什么我需要的是一种方法:

constexpr std::array<int, 3> a1 = {1,2,3};
constexpr std::array<int, 2> a2 = {4,5};
constexpr auto a3 = make_flattened_array (a1,a2);

我使用 gcc 4.8.4 (arm-none-eabi),如果需要,可以使用 std=c++11 或 c++1y 选项进行编译。

最佳答案

注意 - 我对您的问题的理解如下:您想加入这两个数组并将结果展平为一个包含其元素串联的单个新数组。

您可以通过三个 C++11+ 概念来实现您的目标:

  1. Variadic templates
  2. constexpr expressions
  3. Parameter pack

您首先创建一个模板(一个空壳)来开始设计您的递归时尚列表展平功能:

template<unsigned N1, unsigned N2>
constexpr std::array<int, N1+N2> concat(const std::array<int, N1>& a1, const std::array<int, N2>& a2){
// TODO
}

到目前为止一切顺利:constexpr 说明符将提示编译器每次可以在编译时评估该函数。

现在是有趣的部分:std::array 有(从 c++1y 开始)一个 constexpr overload for the operator[] ,这意味着你可以写类似的东西

template<unsigned N1, unsigned N2>
constexpr std::array<int, N1+N2> concat(const std::array<int, N1>& a1, const std::array<int, N2>& a2){
return std::array<int,N1+N2>{a1[0],a1[1],a1[2],a2[0],a2[1]};
}

(注意 aggregate-initialization 从一系列整数值初始化对象)

显然,手动硬编码对两个数组的值的所有索引访问并不比仅仅声明连接数组本身更好。将拯救这一天的概念如下:Parameter Packs .模板参数包是接受 0 个或多个模板参数的模板参数。具有至少一个参数包的模板称为可变参数模板

很酷的是能够将参数包扩展到指定位置,例如:

#include <iostream>
#include <array>

template<unsigned... Num>
std::array<int, 5> function(const std::array<int,5>& source) {
return std::array<int,5>{source[Num]...};
}


int main() {
std::array<int,5> source{7,8,9,10,11};
std::array<int,5> res = function<0,1,2,3,4>(source);

for(int i=0; i<res.size(); ++i)
std::cout << res[i] << " "; // 7 8 9 10 11

return 0;
}

所以我们现在唯一需要的是能够在编译时生成“索引系列”,例如

std::array<int,5> res = function<0,1,2,3,4>(source);
^ ^ ^ ^ ^

在这一点上,我们可以再次利用参数包和继承机制:想法是有一个深度嵌套的层次结构 derived : base : other_base : another_base : ...将索引“累积”到参数包中并在索引达到 0 时终止“递归”的类。如果您不理解前面的句子,请不要担心,看看以下示例:

std::array<int, 3> a1{42,26,77};

// goal: having "Is" = {0,1,2} i.e. a1's valid indices
template<unsigned... Is> struct seq;

我们可以通过以下方式生成索引序列:

template<unsigned N, unsigned... Is>
struct gen_seq : gen_seq<N-1, Is...>{}; // each time decrement the index and go on
template<unsigned... Is>
struct gen_seq<0 /*stops the recursion*/, Is...> : /* generate the sequence */seq<Is...>{};

std::array<int, 3> a1{42,26,77};
gen_seq<3>{};

无论如何还是缺少一些东西:上面的代码将以 gen_seq<3, (nothing)> 开头并实例化指定的模板,该模板将实例化 gen_seq<2, (nothing)> 作为其将实例化 gen_seq<1 的基类, (nothing)> 作为它的基类,它将实例化 gen_seq<0, (nothing)> 作为它的基类,它将实例化 seq<(nothing)> 作为最终序列。

序列是'(nothing)',有问题..

为了将索引“累积”到参数包中,您需要在每次递归时将减少的索引的拷贝“添加”到参数包:

template<unsigned N, unsigned... Is>
struct gen_seq : gen_seq<N-1, /*This copy goes into the parameter pack*/ N-1, Is...>{};

template<unsigned... Is>
struct gen_seq<0 /*Stops the recursion*/, Is...> : /*Generate the sequence*/seq<Is...>{};
template<unsigned... Is> struct seq{};

// Using '/' to denote (nothing)
gen_seq<3,/> : gen_seq<2, 2,/> : gen_seq<1, 1,2,/> : gen_seq<0, 0,1,2,/> : seq<0,1,2,/> .

所以现在我们能够将所有部分重新收集在一起并生成两个索引序列:一个用于第一个数组,一个用于第二个数组,并将它们连接在一起形成一个新的返回数组,该数组将保存连接和展平的 union 的两个数组(就像将它们附加在一起)。

此时,以下代码应该很容易理解:

#include <iostream>
#include <array>

template<unsigned... Is> struct seq{};
template<unsigned N, unsigned... Is>
struct gen_seq : gen_seq<N-1, N-1, Is...>{};
template<unsigned... Is>
struct gen_seq<0, Is...> : seq<Is...>{};

template<unsigned N1, unsigned... I1, unsigned N2, unsigned... I2>
// Expansion pack
constexpr std::array<int, N1+N2> concat(const std::array<int, N1>& a1, const std::array<int, N2>& a2, seq<I1...>, seq<I2...>){
return { a1[I1]..., a2[I2]... };
}

template<unsigned N1, unsigned N2>
// Initializer for the recursion
constexpr std::array<int, N1+N2> concat(const std::array<int, N1>& a1, const std::array<int, N2>& a2){
return concat(a1, a2, gen_seq<N1>{}, gen_seq<N2>{});
}

int main() {
constexpr std::array<int, 3> a1 = {1,2,3};
constexpr std::array<int, 2> a2 = {4,5};

constexpr std::array<int,5> res = concat(a1,a2);
for(int i=0; i<res.size(); ++i)
std::cout << res[i] << " "; // 1 2 3 4 5

return 0;
}

http://ideone.com/HeLLDm


引用资料:

https://stackoverflow.com/a/13294458/1938163

http://en.cppreference.com/

http://en.wikipedia.org

关于c++11 constexpr 将 std::array 列表展平为数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25068481/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com