I am writing a function to calculate an offset of an element in a POD struct in my pod_reflection library. Complete header link.
To calculate an offset of a next element I need to know the packing value of a struct (which can be set via #pragma pack(N)
). I assumed that alignof
operator yields this value since, for example, for pack(1)
it returned 1:
#pragma pack(push, 1)
struct packed
{
char a;
int b;
};
#pragma pack(pop)
static_assert(alignof(packed) == 1, "");
I found out that I was wrong. If a structure contains double
(8 bytes), alignof
yields 8. So the calculated offset will be invalid.
Here is the code I use to calculate an offset.
template<typename POD, typename TupleFeed = basic_feed>
constexpr size_t pod_packing()
{
return alignof(POD);
}
// TODO: check this function!
template<size_t I, typename POD, typename TupleFeed>
class pod_elem_offset
{
static_assert(!std::is_same<undeduced, pod_element_t<I, POD, TupleFeed>>::value,
"Can't get an offset for an undeduced POD element!");
template<size_t Indx>
constexpr static size_t pod_elem_size()
{
return sizeof(pod_element_t<Indx, POD, TupleFeed>);
}
public:
constexpr static std::ptrdiff_t packing = pod_packing<POD, TupleFeed>();
constexpr static std::ptrdiff_t value()
{
return get_value(tag_s<0>(), 0);
}
private:
// stop case
constexpr static std::ptrdiff_t get_value(tag_s<I>, size_t offset)
{
return offset;
}
// general recursion
template<size_t N>
constexpr static std::ptrdiff_t get_value(tag_s<N>, size_t offset)
{
static_assert(!std::is_same<undeduced, pod_element_t<N, POD, TupleFeed>>::value,
"Can't get an offset for a POD element: failed to deduce one of POD elements' type!");
// TODO: implement with packing
return get_value(tag_s<N + 1>(),
!((offset + pod_elem_size<N>()) % packing) ||
packing - (offset + pod_elem_size<N>()) % packing >= pod_elem_size<N + 1>() ?
offset + pod_elem_size<N>() :
offset + pod_elem_size<N>() +
packing - (offset + pod_elem_size<N>()) % packing
);
}
};
How can I deduce the packing value of a struct for padding calculation?
I figured out a workaround. Not sure it would suffice for every possible packing.
template<typename POD>
constexpr size_t pod_packing()
{
return sizeof(POD) % 4 ?
sizeof(POD) % 4 :
4;
}
Aucun commentaire:
Enregistrer un commentaire