Наскільки я можу сказати, це неможливо, якщо ви хочете мати обох членів. Але ви можете спеціалізуватися та мати лише одного з членів, коли тип однаковий та порожній:
template <typename T, typename S, typename = void>
struct Empty{
[[no_unique_address]] T t;
[[no_unique_address]] S s;
constexpr T& get_t() noexcept { return t; };
constexpr S& get_s() noexcept { return s; };
};
template<typename TS>
struct Empty<TS, TS, typename std::enable_if_t<std::is_empty_v<TS>>>{
[[no_unique_address]] TS ts;
constexpr TS& get_t() noexcept { return ts; };
constexpr TS& get_s() noexcept { return ts; };
};
Звичайно, решту програми, яка використовує членів, потрібно було б змінити для вирішення випадку, коли є лише один учасник. Не має значення, який член використовується в цьому випадку - адже це об'єкт без громадянства, що не має унікальної адреси. Показані функції членів повинні зробити це простим.
на жаль, sizeof(Empty<Empty<A,A>,A>{})==2
де A - абсолютно порожня структура.
Ви можете ввести більше спеціалізацій для підтримки рекурсивного стиснення порожніх пар:
template<class TS>
struct Empty<Empty<TS, TS>, TS, typename std::enable_if_t<std::is_empty_v<TS>>>{
[[no_unique_address]] Empty<TS, TS> ts;
constexpr Empty<TS, TS>& get_t() noexcept { return ts; };
constexpr TS& get_s() noexcept { return ts.get_s(); };
};
template<class TS>
struct Empty<TS, Empty<TS, TS>, typename std::enable_if_t<std::is_empty_v<TS>>>{
[[no_unique_address]] Empty<TS, TS> ts;
constexpr TS& get_t() noexcept { return ts.get_t(); };
constexpr Empty<TS, TS>& get_s() noexcept { return ts; };
};
Навіть більше, стискати щось на кшталт Empty<Empty<A, char>, A>
.
template <typename T, typename S>
struct Empty<Empty<T, S>, S, typename std::enable_if_t<std::is_empty_v<S>>>{
[[no_unique_address]] Empty<T, S> ts;
constexpr Empty<T, S>& get_t() noexcept { return ts; };
constexpr S& get_s() noexcept { return ts.get_s(); };
};
template <typename T, typename S>
struct Empty<Empty<S, T>, S, typename std::enable_if_t<std::is_empty_v<S>>>{
[[no_unique_address]] Empty<S, T> st;
constexpr Empty<S, T>& get_t() noexcept { return st; };
constexpr S& get_s() noexcept { return st.get_t(); };
};
template <typename T, typename S>
struct Empty<T, Empty<T, S>, typename std::enable_if_t<std::is_empty_v<T>>>{
[[no_unique_address]] Empty<T, S> ts;
constexpr T& get_t() noexcept { return ts.get_t(); };
constexpr Empty<T, S> get_s() noexcept { return ts; };
};
template <typename T, typename S>
struct Empty<T, Empty<S, T>, typename std::enable_if_t<std::is_empty_v<T>>>{
[[no_unique_address]] Empty<S, T> st;
constexpr T& get_t() noexcept { return st.get_s(); };
constexpr Empty<S, T> get_s() noexcept { return st; };
};
T
себе? Це створило б різні типи. Зараз факт, що обидваWrapper
спадкують відT
вас, стримує вас ...