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

我想通过一组可变参数模板参数来描述静态嵌入到程序代码中(最好在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))

        } };

}

但是让客户手动计算偏移量看起来容易出错且乏味。


小怪兽爱吃肉
浏览 538回答 3
3回答

慕的地10843

为了进行编译时间累积,您必须具有一个编译时间序列。一种简单的方法是使用可变参数模板。每个条目将是特定元素的标识符和大小,或特定元素的标识符和类型。顶级条目将是Layout:template<std::size_t offset, typename Key, typename... Entries>struct LayoutHelper {&nbsp; 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...>{&nbsp; &nbsp; typedef typename prepend&nbsp; &nbsp; &nbsp; &nbsp; < ProcessedEntry< Key, id0, D0, offset >&nbsp; &nbsp; &nbsp; &nbsp; , typename LayoutHelper<offset+sizeof(D0), Key, Entries...>::type&nbsp; &nbsp; &nbsp; &nbsp; >::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...>> {&nbsp; 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别名删除重复项会很好。

慕虎7371278

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

猛跑小猪

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