Search code examples
c++structmultiple-inheritance

Understanding different padding rules between gcc/clang vs msvc2015 when inheriting multiple empty classes


I am seeing different behaviours when it comes to multiple inheritance of empty classes in gcc/clang vs msvc2015. I was wondering if somebody would know what in the standard allows for such differences.

#include <cstdint>
using namespace std;

class Empty1 {};
static_assert(sizeof(Empty1) == 1, "Expected size of 1 for Empty1");

class Empty2 {};
static_assert(sizeof(Empty2) == 1, "Expected size of 1 for Empty2");

class Empty3 : Empty2, Empty1 {};
static_assert(sizeof(Empty3) == 1, "Expected size of 1 for Empty3");

class Int1 { uint32_t i; };
static_assert(sizeof(Int1) == 4, "Expected size of 4 for Int1");

class Int2 : Empty1 { uint32_t i; };
static_assert(sizeof(Int2) == 4, "Expected size of 4 for Int2");

class Int3 : Empty2 { uint32_t i; };
static_assert(sizeof(Int3) == 4, "Expected size of 4 for Int3");

class Int4 : Empty3 { uint32_t i; };
static_assert(sizeof(Int4) == 8, "Expected size of 8 for Int4");
static_assert(sizeof(Int4) == 4, "Expected size of 4 for Int4");

This codes, on msvc2015 generates:

error C2338: Expected size of 4 for Int4

While gcc and clang generate this instead:

error: static_assert failed "Expected size of 8 for Int4"

In other words, msvc2015 does not add any byte when inheriting from an empty class, but it does when inheriting from multiple ones. Is undefined behaviour in C++?


Solution

  • By default, MSVC doesn't do this optimization so that code it compiles can be ABI compatible with older versions of the compiler. However, if you use __declspec(empty_bases), you can tell MSVC to enable this optimization:

    #ifdef _MSC_VER
    #define EBO_ENABLE __declspec(empty_bases)
    #else
    #define EBO_ENABLE
    #endif
    
    class EBO_ENABLE Empty3 : Empty2, Empty1 {};
    static_assert(sizeof(Empty3) == 1, "Expected size of 1 for Empty3");
    

    Live on Godbolt