Increase merging by combining a parameter package with a lambda

In the code below (C ++ 14, no 'fold' from C ++ 17), I am trying to automatically calculate fixed offsets for a class field at compile time using merge merge acceleration, parameter packages and lambda. Unfortunately, this leads to a compile-time error ... Is it possible to do something like this?

[EDIT: something else bothers me: it's not quite what I want. I would like _size from ControlledLayout2 to be available at compile time (why I made it static), and not just when calling the constructor]

template <typename T, uint32_t size> struct Field2 { typedef T _type; static const uint32_t _size; static uint32_t _offset; }; template <typename T, uint32_t size> const uint32_t Field2<T,size>::_size = size; template <typename T, uint32_t size> uint32_t Field2<T,size>::_offset = 0; template <typename ... T> struct ControlledLayout2 { static uint32_t _size; ControlledLayout2(T... args) { _size = fold({args...}, 0, [&](uint32_t s, T field) { return T::_offset = s + T::_size; }...); }; }; ... ControlledLayout2<Field2<int, 32>, Field2<char, 1>, Field2<long, 64>> cl; cout << cl._size << endl; ... 

And the compiler error:

 error: parameter not expanded with '...'; _size = accumulate({args...}, ... 
+4
source share
1 answer

Since you want to do all the calculations at compile time, boost::fusion::fold not suitable for this.

Instead, I calculated size and offset using constexpr in ControlledLayout2 :

 #include <iostream> #include <tuple> template <typename T, uint32_t Size> struct Field2 { using type = T; static const uint32_t size = Size; }; template <typename T, typename U> struct selector; template <typename T, std::size_t... Is> struct selector<T, std::index_sequence<Is...>> { using type = std::tuple<typename std::tuple_element<Is, T>::type...>; }; template <std::size_t N, typename... Ts> struct remove_last_n { using Indices = std::make_index_sequence<sizeof...(Ts)-N>; using type = typename selector<std::tuple<Ts...>, Indices>::type; }; template <typename ... Ts> struct ControlledLayout2 { static constexpr uint32_t get_size() { return size_impl<Ts...>(); } template <typename X, typename... Xs> static constexpr uint32_t size_impl(typename std::enable_if<(sizeof...(Xs) > 0)>::type* = 0) { return ((X::size) + size_impl<Xs...>()); } template <typename X> static constexpr uint32_t size_impl() { return X::size; } template <std::size_t field_number> static constexpr uint32_t offset() { using Tuple = typename remove_last_n<sizeof...(Ts)-field_number, Ts...>::type; return offset_impl(Tuple{}); } template <typename... Xs> static constexpr uint32_t offset_impl(std::tuple<Xs...>) { return size_impl<Xs...>(); } static const uint32_t size = get_size(); }; int main() { using Layout = ControlledLayout2<Field2<int, 32>, Field2<char, 1>, Field2<char, 128>, Field2<long, 64> >; std::cout << Layout::size << std::endl; std::cout << Layout::offset<3>() << std::endl; } 

Exit

 225 161 

live on coliru

+2
source

All Articles