Skip to content

<xstd/misc/type_traits/empty_base_type.hpp>

xstd::empty_base_type

template<class Tag = void>
struct empty_base_type {};

A tagged empty class that keeps the place of a base class that is not there.

Template parameters

Parameter Meaning
Tag Distinguishes one empty base from another. Defaults to void, and distinct tags give distinct types, so a class can derive from more than one.

Notes

  • It is an empty, regular, trivial class, whose special members do not throw.
  • It declares no comparison, so none reaches a class derived from it.

Example

#include <xstd/misc/type_traits/empty_base_type.hpp> // empty_base_type
#include <iostream>                                  // boolalpha, cout
#include <type_traits>                               // conditional_t

struct use_count
{
        int uses = 0;
};

// A widget counts its uses only where Counted holds, and where it does not its base costs no storage.
template<bool Counted>
struct widget : std::conditional_t<Counted, use_count, xstd::empty_base_type<use_count>>
{
        int id = 0;
};

// Whether a class counts its uses, read from whether it has the member that counts them.
template<class T>
concept counts_uses = requires (T const& t) { t.uses; };

auto main() -> int
{
        auto counted = widget<true>();
        ++counted.uses;
        std::cout << "uses: " << counted.uses << '\n';

        std::cout << std::boolalpha;
        std::cout << "widget<true> counts its uses: " << counts_uses<widget<true>> << '\n';
        std::cout << "widget<false> counts its uses: " << counts_uses<widget<false>> << '\n';
        std::cout << "sizeof(widget<false>) == sizeof(int) is " << (sizeof(widget<false>) == sizeof(int)) << '\n';
}

Output:

uses: 1
widget<true> counts its uses: true
widget<false> counts its uses: false
sizeof(widget<false>) == sizeof(int) is true

See also

Entity Relation
empty_member_type the same for a data member, and comparable
conditional_data_member a member's type, or an empty type where a condition fails