Creating an array initializer from a tuple or variadic template parameters

Solution 1:

In order for compile time accumulation to occur, you have to have a compile time sequence.

An easy way to do this would be to use variadic templates. Each entry would be an identifier and a size of a particular element, or the identifier and type of a particular element.

The top level bundle of entries would be a 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...> {};

Each entry would be:

template<typename Key, Key identifier, typename Data>
struct Entry {};

Then, we do something like this:

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

Use would look like:

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

which, after writing or finding a prepend that takes an element and a tuple, and prepends the element at the front, would mean that Layout<blah>::type would contain a tuple that describes the layout of your data.

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;

You'd then unpack that tuple into a std::array if you wanted. You'd use the indexes trick to do this (there are many examples on stack overflow that use this same trick in different ways).

Or, you could take your ProcessedEntry and add in methods to access data, then write a Key searching compile-time program that walks the tuple, looking for the matching Key, and then returns the offset and size (or even type) as compile time code. Maybe take an array<N, unsigned char> as an argument and do the reintepret_cast, returning a reference-to-data.

Removing the repeated FooEnum would be good via using aliases.