In C++20, it will be possible to do what you're trying to do directly:
template <typename T, typename A = some_type_with_size_0>
struct s {
T t;
[[no_unique_address]] A aux;
};
See https://en.cppreference.com/w/cpp/language/attributes/no_unique_address.
In C++17, there's no straightforward way to specify a member that conditionally disappears. You need to write a full-blown partial specialization, like so:
template <typename T, typename A = void>
struct s {
T t;
A aux;
};
template <typename T>
struct s<T, void> {
T t;
};
This unfortunately requires you to repeat yourself in typing out all the common members (in this case only t
). To avoid this, we can stick the conditionally present members in a base class:
template <typename T, typename A = void>
struct s : optional_aux<A> {
T t;
};
template <typename A>
struct optional_aux {
A aux;
};
template <>
struct optional_aux<void> { };
In the case where A = void
, this base class is empty, so the compiler has discretion to remove it entirely, making sizeof(s<T, void>)
potentially equal to sizeof(T)
. The [[no_unique_address]]
attribute basically makes empty base class optimization available for members as well.