<xstd/misc/type_traits/empty_member_type.hpp>¶
xstd::empty_member_type¶
template<class Tag = void>
struct empty_member_type {
empty_member_type() = default;
template<class... Args>
requires ((not same_as<remove_cvref_t<Args>, empty_member_type>) and ...)
constexpr explicit empty_member_type(Args&&...) noexcept;
friend auto operator<=>(empty_member_type, empty_member_type) -> strong_ordering = default;
};
A tagged empty class that keeps the place of a data member that is not there.
Template parameters¶
| Parameter | Meaning |
|---|---|
Tag |
Distinguishes one empty member from another. Defaults to void, and distinct tags give distinct types. |
Member functions¶
- The variadic constructor ignores its arguments, so an enclosing class can construct the member as it would the
type it stands in for.
- Constraints: No
Argsis the class itself, so copying from a mutable lvalue stays the trivial copy rather than the variadic constructor, which would match that lvalue better.
- Constraints: No
operator<=>: every two of its values compare equal and equivalent.
Notes¶
- It is an empty, regular, totally ordered, trivial class, whose special members do not throw, usable in constant expressions.
- Its comparisons reach a class derived from it, and not a class that holds it as a member.
Example¶
#include <xstd/misc/type_traits/empty_member_type.hpp> // empty_member_type
#include <iostream> // boolalpha, cout
#include <string> // string
#include <type_traits> // conditional_t
// An entry keeps a label only where Labelled holds; elsewhere an empty stand-in is built and compared in its place.
template<bool Labelled>
struct entry
{
int value;
std::conditional_t<Labelled, std::string, xstd::empty_member_type<std::string>> label;
[[nodiscard]] entry(int v, char const* name)
: value(v)
, label(name)
{}
[[nodiscard]] friend auto operator==(entry const&, entry const&) -> bool = default;
};
auto main() -> int
{
std::cout << std::boolalpha;
std::cout << "labelled entries 1 \"one\" and 1 \"uno\" are equal: " << (entry<true>(1, "one") == entry<true>(1, "uno")) << '\n';
std::cout << "unlabelled entries 1 \"one\" and 1 \"uno\" are equal: " << (entry<false>(1, "one") == entry<false>(1, "uno")) << '\n';
std::cout << "unlabelled entries 1 \"one\" and 2 \"two\" are equal: " << (entry<false>(1, "one") == entry<false>(2, "two")) << '\n';
}
Output:
labelled entries 1 "one" and 1 "uno" are equal: false
unlabelled entries 1 "one" and 1 "uno" are equal: true
unlabelled entries 1 "one" and 2 "two" are equal: false
See also¶
| Entity | Relation |
|---|---|
empty_base_type |
the same for a base class, without comparisons |
conditional_data_member |
picks this type where a condition fails |
XSTD_NO_UNIQUE_ADDRESS |
lets a member of this type take no storage |