Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Layout with union and empty base class on Windows

Given the following program:

#include <cstdio>
#include <type_traits>
#include <utility>

struct EmptyClass {};

template <typename T, typename U>
struct Storage {
 protected:
  union Union {
    T t;
    U u;
  } data;

  char flag = false;
};

class AnotherEmptyClass {};

template <typename T, typename U>
class Derived : private Storage<T, U>, public AnotherEmptyClass {};

static_assert(std::is_standard_layout_v<Derived<char, EmptyClass>>);

int main() {
  printf("Storage<char, EmptyClass>: %zu\n", sizeof(Storage<char, EmptyClass>));
  printf("Derived<char, EmptyClass>: %zu\n", sizeof(Derived<char, EmptyClass>));

  printf("Storage<char, char>: %zu\n", sizeof(Storage<char, char>));
  printf("Derived<char, char>: %zu\n", sizeof(Derived<char, char>));
}

this outputs 2 2 2 2 on Linux, but 2 3 2 2 on Windows (both with clang and MSVC).

Why is that? It seems that using EmptyClass as a member of the union prevents empty-base class optimization on the derived class. But for a standard-layout type, empty base class optimization is required. Or is there a different reason for this layout?

like image 359
Simon Avatar asked Mar 24 '21 12:03

Simon


1 Answers

template <typename T, typename U>
class __declspec(empty_bases) Derived : private Storage<T, U>, public AnotherEmptyClass {};

Will do the job but I don't know, why this behavior is disabled by default for the Microsoft compiler, even for the 2019 version with latest framework and active conformance mode. Only a theory: This seems to be a long term issue and maybe the drawbacks of breaking functional code in a massive way were evaluated as not been reasonable.

like image 197
Secundi Avatar answered Oct 19 '22 00:10

Secundi