Search code examples
c++paddingtraitsmemory-layout

how to get the size of the padding at the end of a class


I have a class A like this:

struct V {
    virtual void f() = 0;
};

struct A {
    int data;
};

struct B : public A , public V {
    void f() override {}
};

MSVC gives me sizeof(A) == 4 and sizeof(B) == 16 on a 64 bit build instead of 12 (sizeof(void*) + sizeof(A)) - so there is a 4 byte padding. Is there a way to get that padding? perhaps with some trait?

The reason I need this is to do an assert like this:

static_assert(sizeof(B) == sizeof(A) + std::is_polymorphic<camera>::value * sizeof(void*));

Meaning that I want to ensure that all data is in the base class, but B should be able to be polymorphic by inheriting from some interface... No new members shall be added to B but it should be allowed to be polymorphic. If I had 2 integers in A there would be 0 padding at the end of B...


Solution

  • I found a solution which seems to work on GCC and clang, at least for the example you gave.

    namespace detail {
    
    template <typename T, int N>
    struct add_padding : add_padding<T, N - 1> {
        char pad;
    };
    
    template <typename T>
    struct add_padding<T, 0> : T {
    };
    
    } // namespace detail
    
    template <typename T, int N = 1, bool = (sizeof(T) == sizeof(detail::add_padding<T, N>))>
    struct padding_size {
        static constexpr int value = padding_size<T, N + 1>::value;
    };
    
    template <typename T, int N>
    struct padding_size<T, N, false> {
        static constexpr int value = N - 1;
    };
    

    It breaks for padding that is not caused by inheriting from different-sized types, and it doesn't work with MSVC at all. So it's not really an answer to your question I'm afraid, but maybe it helps someone else. Here's a live example.