为了账号安全,请及时绑定邮箱和手机立即绑定

从元组或可变参数模板参数创建数组初始化器

从元组或可变参数模板参数创建数组初始化器

C++
小怪兽爱吃肉 2019-11-21 10:12:03
我想通过一组可变参数模板参数来描述静态嵌入到程序代码中(最好在ROM部分中)的持久性内存布局(例如Flash或EEPROM设备)的描述,其中在编译时会自动计算必要的偏移量。目标是创建一个合适的数组初始化器,该初始化器可以在运行时进行迭代,而不会受到限制std::get(std::tuple),而这需要编译时索引。第一种方法我创建了一个简单的数据项描述符类,该类将一个特定的ID(应由客户端以枚举类型提供)绑定到数据布局(偏移量和大小):template    < typename ItemIdType    >struct DataItemDescBase{    const ItemIdType id;    const std::size_t size;    const std::size_t offset;    DataItemDescBase(ItemIdType id_, std::size_t size_, std::size_t offset_)    : id(id_)    , size(size_)    , offset(offset_)    {    }    DataItemDescBase(const DataItemDescBase<ItemIdType>& rhs)    : id(rhs.id)    , size(rhs.size)    , offset(rhs.offset)    {    }};客户端应使用绑定到特定数据类型和偏移量的此类:template    < typename DataType    , typename ItemIdType    >struct DataItemDesc: public DataItemDescBase<ItemIdType>{    typedef DataType DataTypeSpec;    DataItemDesc(ItemIdType id_, std::size_t offset_ = 0)    : DataItemDescBase(id_,sizeof(DataTypeSpec),offset_)    {    }    DataItemDesc(const DataItemDesc<DataType,ItemIdType>& rhs)    : DataItemDescBase(rhs)    {    }};最后,我想使用a std::array存储具体的数据布局:const std::array<DataItemDescBase<ItemIdType>,NumDataItems> dataItemDescriptors;对于客户端,我想从a std::tuple或可变参数模板参数列表中提供一个数组初始化程序,因此,在编译时,将根据前一个元素的offset +大小自动计算后续数组元素的offset。当前有效的是,客户端可以使用以下代码初始化数组:namespace{    static const std::array<DataItemDescBase<DataItemId::Values>,4> theDataLayout =        { { DataItemDesc<int,DataItemId::Values>             ( DataItemId::DataItem1 )        , DataItemDesc<short,DataItemId::Values>             ( DataItemId::DataItem2             , sizeof(int))        , DataItemDesc<double,DataItemId::Values>             ( DataItemId::DataItem3             , sizeof(int) + sizeof(short))        , DataItemDesc<char[10],DataItemId::Values>             ( DataItemId::DataItem4             , sizeof(int) + sizeof(short) + sizeof(double))        } };}但是让客户手动计算偏移量看起来容易出错且乏味。
查看完整描述

3 回答

?
慕的地10843

TA贡献1785条经验 获得超8个赞

为了进行编译时间累积,您必须具有一个编译时间序列。


一种简单的方法是使用可变参数模板。每个条目将是特定元素的标识符和大小,或特定元素的标识符和类型。


顶级条目将是Layout:


template<std::size_t offset, typename Key, typename... Entries>

struct LayoutHelper {

  typedef std::tuple<> type;

};

template<typename Key, typename... Entries>

struct Layout:LayoutHelper<0, Key, Entries...> {};

每个条目将是:


template<typename Key, Key identifier, typename Data>

struct Entry {};

然后,我们执行以下操作:


template<typename Key, Key identifier, typename Data, std::size_t Offset>

struct ProcessedEntry {};


template<std::size_t offset, typename Key, Key id0, typename D0, typename... Entries>

struct LayoutHelper<offset, Key, Entry<Key, id0, D0>, Entries...>

{

    typedef typename prepend

        < ProcessedEntry< Key, id0, D0, offset >

        , typename LayoutHelper<offset+sizeof(D0), Key, Entries...>::type

        >::type type;

};

使用看起来像:


Layout< FooEnum, Entry< FooEnum, eFoo, char[10] >, Entry< FooEnum, eFoo2, double > > layout;

在编写或找到一个prepend包含一个元素和一个tuple并在最前面添加该元素的a之后,这意味着Layout<blah>::type将包含一个tuple描述数据布局的a 。


template<typename T, typename Pack>

struct prepend;

template<typename T, template<typename...>class Pack, typename... Ts>

struct prepend<T, Pack<Ts...>> {

  typedef Pack<T, Ts...> type;

};

// use: prepend<int, std::tuple<double>::type is std::tuple<int, double>

// this removes some ::type and typename boilerplate, if it works in your compiler:

template<typename T, typename Pack>

using Prepend = typename prepend<T, Pack>::type;

然后,如果需要,可以将其解压缩tuple为一个std::array。您可以使用索引技巧来做到这一点(堆栈溢出中有许多示例以不同的方式使用了相同的技巧)。


或者,您可以使用ProcessedEntry并添加方法来访问数据,然后编写一个Key搜索编译时程序,该程序遍历tuple,寻找匹配项Key,然后返回offsetand size(甚至类型)作为编译时代码。也许将an array<N, unsigned char>作为参数并执行reintepret_cast,返回对的引用data。


FooEnum通过using别名删除重复项会很好。


查看完整回答
反对 回复 2019-11-21
?
慕虎7371278

TA贡献1802条经验 获得超4个赞

“然后您可以将该元组解压缩为std :: array”,可以在此进行详细说明。我没有为此使用什么数组元素类型。提供的基本类型ProcessedEntry,仅仅持续了数据idoffsetsize。我需要在运行时通过id访问特定的布局条目,以使适当的访问器类可以访问特定的布局条目,并计算要从具体的持久性存储设备读取的地址和数据大小(或者我是否需要对它进行运行时计算(不确定) ?)

查看完整回答
反对 回复 2019-11-21
?
猛跑小猪

TA贡献1858条经验 获得超8个赞

“会花点时间,很难在手机上键入代码”哈!您正在寻找书呆子; o),因此应为此提供一个应用程序!不,问题需要在下个星期左右找到合适的解决方案。然后看看我的更新。其实我上了几天假节日; O)...

查看完整回答
反对 回复 2019-11-21
  • 3 回答
  • 0 关注
  • 537 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信