It’s good and common to want to use regular data types. But still creating them is more difficult than it should be.

This article is part of a series on the history of regular data type in C++.

Around 2018 I showed how to do it using tie_members and macros:

1
2
3
4
5
6
7
8
9
10
11
struct person {
  std::string first_name;
  std::string last_name;
  int age{};
};

inline auto tie_members(const person & x) noexcept {
  return tie_with_check<person>(x.first_name, x.last_name, x.age);
}

MAKE_STRICT_TOTALY_ORDERED(person)

Then in this series of articles I showed hot to do it using the spaceship operator:

1
2
3
4
5
6
7
8
struct person {
  std::string first_name;
  std::string last_name;
  int age{};

  constexpr std::strong_ordering
    operator<=>(const person &) const noexcept = default;
};

Using the spaceship operator is an improvement, but still has issues.

Where I would like to get is something like:

1
2
3
4
5
regular_struct person {
  std::string first_name;
  std::string last_name;
  int age;
};

The definition for the regular_struct (potentially user defined) should create the regular boileplate: default constructor (including defaulting the int to 0, copy, move, comparisons, etc.