C ++ 11 constexpr扁平化的std ::数组的数组列表 [英] c++11 constexpr flatten list of std::array into array

查看:154
本文介绍了C ++ 11 constexpr扁平化的std ::数组的数组列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我与C ++ 11,constexpr和模板元编程开始,似乎一个很好的方式,以节省小小的单片机稀缺的RAM。

I am beginning with c++11, constexpr and template metaprogramming seems a nice way to save scarce ram on tiny microcontroler.

是否有写模板弄平constexpr阵列的列表的方式,什么
我需要的是一个办法做到:

Is there a way to write a template to flatten a list of constexpr array, what I need is a way to do :

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),并能与性病编译= C ++ 11或C ++,如果需要的话1Y选项。

I use gcc 4.8.4 (arm-none-eabi), and can compile with std=c++11 or c++1y option if it is needed.

推荐答案

的通知 - 我明白你的问题如下:你想加入这两个阵列和结果拼合到包含单个新阵它们的元素的串联。

Notice - I understood your question as follows: you want to join those two arrays and flatten the result into a single, new array containing the concatenation of their elements.

您可以达成你的目标有三个C ++ 11 +概念:

You can accomplish your goal with three C++11+ concepts:


  1. 可变参数模板

  2. constexpr前pressions

  3. 参数包

您开始通过创建一个模板(一个空壳)开始设计递归的方式列表压扁功能:

You start by creating a template (an empty shell) to start designing your recursive-fashion list flattening function:

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 说明会提示编译器编译时每次它可以评估功能

so far so good: the constexpr specifier will hint the compiler to compile-time evaluate that function each time it can.

现在的有趣的部分:性病::阵列(因为 C ++ 1Y )一 constexpr过载为运营商[] ,这意味着你可以写的东西像

Now for the interesting part: std::array has (since c++1y) a constexpr overload for the operator[], this means you can write something like

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

(注意,<一个href=\"http://en.cp$p$pference.com/w/cpp/language/aggregate_initialization\">aggregate-initialization从一系列的整数值的初始化的对象)

(notice the aggregate-initialization to initialize the object from a series of integer values)

显然手动硬编码的所有索引访问两个数组的值不超过刚刚宣布级联阵列本身要好。这将拯救世界的理念是:参数包。模板参数包是接受零个或多个模板参数模板参数。至少有一个参数包的模板被称为可变参数模板

Obviously manually hard-coding all the index accesses to the values of the two arrays is no better than just declaring the concatenated array itself. The concept that will save the day is the following: Parameter Packs. A template parameter pack is a template parameter that accepts 0 or more template arguments. A template with at least one parameter pack is called variadic template.

很酷的事情是扩大了参数包到指定位置一样的能力:

The cool thing is the ability of expanding the parameter pack into specified locations like:

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

所以,我们现在唯一需要的是能够编译时产生指数系列像

So the only thing we need right now is to be able to compile-time generate the "index series" like

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

在这一点上,我们可以再次与继承机制一起走参数包优势:想法是有衍生的深层嵌套层次:基础:other_base:another_base:... 班这将收集索引到参数包,当指数达到0。如果您不理解previous一句话也别担心,看看终止递归在下面的例子:

At this point we can again take advantage of the parameter packs in conjunction with an inheritance mechanism: the idea is to have a deeply nested hierarchy of derived : base : other_base : another_base : ... classes which would "accumulate" the indices into the parameter pack and terminate the "recursion" when the index reaches 0. If you didn't understand the previous sentence don't worry and take a look at the following example:

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;

我们可以生成指数以下列方式的序列:

we can generate a sequence of indices in the following way:

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

有什么东西丢失反正:在code以上将与gen_seq&LT启动; 3,(无)>和实例指定的模板将实例化gen_seq 2,(无)>作为它的基类,将实例化gen_seq&LT; 1,(无)>作为它的基类,将实例化gen_seq℃下,(无)>作为它的基类,将实例化以次≤(无)>的最终序列。

There's something missing anyway: the code above will start with gen_seq<3, (nothing)> and instantiate the specified template which will instantiate the gen_seq<2, (nothing)> as its base class that will instantiate the gen_seq<1, (nothing)> as its base class that will instantiate the gen_seq<0, (nothing)> as its base class that will instantiate the seq<(nothing)> as final sequence.

序列为(无),什么是错的。

The sequence is '(nothing)', something is wrong..

在以积累的索引到参数包你需要在指数下降到参数包在每个递归的副本添加:

In order to "accumulate" the indices into the parameter pack you need to "add a copy" of the decreased index to the parameter pack at each recursion:

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,/> .

所以现在我们能够把所有的作品一起回忆并生成指数的两个序列:一个是第一阵列和一个第二阵列一起将它们连接起来成为一个新的返回数组将举行级联和工会夷为平地两个阵列(如附加在一起)。

so now we're able to recollect all the pieces together and generate two sequences of indices: one for the first array and one for the second array and concatenate them together into a new return array which will hold the concatenated and flattened union of the two arrays (like appending them together).

以下code,在这一点上,应该很容易的COM prehensible:

The following code, at this point, should be easily comprehensible:

#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

参考文献:

<一个href=\"http://stackoverflow.com/a/13294458/1938163\">http://stackoverflow.com/a/13294458/1938163

HTTP://en.cp$p$pference.com/

http://en.wikipedia.org

这篇关于C ++ 11 constexpr扁平化的std ::数组的数组列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆