我正在研究一个Arduino项目,这意味着C方言目前是C 11的gnu 11超集,并且stdlib不可用(没有元组,没有数组,没有任何东西;命名空间std只是空的!).
出于优化原因(cpu有16K的FLASH,2K的RAM和这个特殊的低电压版本运行在8MHz)我希望编译器尽可能地预先计算以提供运行时代码,尤其是中断服务程序,“友好的“数据.
现在我想做的是以下内容:
给定一个(唯一的)整数列表,我想提取与任意过滤器匹配的值.
然后我想构建一个索引表,允许通过它们的初始索引到达过滤后的元素
例如2,10,4,7,9,3,滤波器值<1. 8可以产生过滤列表2,3和索引表0,-1,1,2,3.
只要索引表保持一致,过滤后的数组中元素的顺序就无关紧要了.
我坚持认为我需要不断的数组.动态生成这些数据非常简单,但我希望编译器能够完成这项工作,而无需在运行时执行单个指令.
初始列表将由普通的#define给出,结果将是常量数组,例如:
#define my_list 2,3 constexpr bool filter (int value) { return value < 8; } const int filtered_list [] = filter_list <filter>(my_list); const size_t filtered_index[] = filter_index<filter>(my_list);
问题是,如果可行的话,如何使用准系统C 11和没有stdlib实现这些filter_list和filter_index模板?
我对错误处理不感兴趣,已经处理了空列表或重复值等异常情况.我宁愿看到最简单的可能实现,即使对数据有效性做出了一些假设.
模板,过滤器或初始列表的确切形式也无关紧要.重要的是从唯一的列表定义中获取数组.
例如,我不介意一种语法,其中列表的每个元素都是单独声明的(虽然我无法想象它是如何工作的).
我更喜欢拥有一个独立的C源代码.另一方面,如果Python可以在几十行中实现,需要隐藏模板的页面,包括重写std :: array和std :: tuple,我宁愿写一些外部预处理器.
解决方法
有一种方法可以避免大多数样板使用函数模板而不是完整类.最后一个类模板是必需的,因为对于c中的函数没有返回类型推导.使用int而不是typename T来跳过不重要的模板参数.当atmel将其工具链更新为gcc5或更新时,c 14支持可以进一步缩小代码.
#define LIST 2,3 constexpr bool less8(int v) { return v < 8; } typedef bool(*predicate)(int); template<int... values> struct seq {}; template<int N> struct array { const int data[N]; }; template<int... values> constexpr array<sizeof...(values)> to_array(seq<values...>) { return {{ values... }}; } template<typename trueType,typename falseType> constexpr falseType select(seq<0>,trueType,falseType) { return {}; } template<typename trueType,typename falseType> constexpr trueType select(seq<1>,falseType) { return {}; } template<int... first,int... second> constexpr seq<first...,second...> append(seq<first...>,seq<second...>) { return {}; } template<predicate p,typename N,typename V> struct filter_impl; template<predicate p,int next> struct filter_impl<p,seq<next>,seq<>> { using type = seq<>; }; template<predicate p,int next,int first,int... rest> struct filter_impl<p,seq<first,rest...>> { using type = decltype( append( select(seq<p(first)>{},seq<next>{},seq<-1>{}),typename filter_impl<p,decltype(select(seq<p(first)>{},seq<next+1>{},seq<next>{})),seq<rest...>>::type{} ) ); }; extern constexpr auto const_indices = to_array(filter_impl<less8,seq<0>,seq<LIST>>::type{});