Skip to content

Support members without a default constructor in CountMembers - #29

Merged
Yaraslaut merged 4 commits into
masterfrom
improvement/count-members-no-default-ctor
Oct 1, 2026
Merged

Yaraslaut merged 4 commits into
masterfrom
improvement/count-members-no-default-ctor

Conversation

@Yaraslaut

Copy link
Copy Markdown
Member

CountMembers reported aggregates containing a member without a default constructor as having no members, which made ToTuple, EnumerateMembers, MemberNames and everything built on them unusable for such types. The count was found by growing an initializer list until the aggregate rejected it, and for these types every list that does not reach the non-default-constructible member is rejected right away. This PR makes counting work for them, and makes it cheaper to compile along the way.

Changes

  • Structured binding packs where available. When the compiler reports __cpp_structured_bindings >= 202411L (P1061), the member count is read from the size of a structured binding pack. This costs constant compile time, and also counts reference members and array members correctly, which the initializer-based approach cannot. Clang offers the feature as an extension before C++26, so its -Wc++26-extensions warning is silenced around that one function.
  • Binary search otherwise. The smallest accepted initializer count is searched linearly (it is non-zero only when there is a non-default-constructible member), and the largest one is then found by doubling and bisecting. This replaces the linear recursion over a growing type pack, which was quadratic: for a 100-member struct it measured roughly 24 ms per type on clang and 13 ms on gcc, versus 6 ms and 2 ms now. An aggregate whose non-default-constructible member sits near the end still needs the linear scan.
  • Readable failure. A type whose members cannot be counted within MaxReflectionMemerCount now fails with a static_assert naming the likely cause, rather than running into the template instantiation depth limit.
  • CI. The clang and gcc jobs installed the compiler version from the matrix but then built with the runner's default clang++ / g++; the versioned compiler is now passed explicitly. The matrix is extended to clang 17–22 and gcc 13–16 (15 and 16 via the official gcc container images), each in C++20, C++23 and, where supported, C++26, so that both counting implementations are covered. clang-cl and macOS jobs are added, together with the macOS test presets they need.

The new CI jobs have not run before this PR: MSVC, clang-cl, AppleClang, the gcc 15/16 containers and the older clang versions are compiling this code for the first time here.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Ar6Ahymw9LhLsnM324z5cV

Yaraslaut and others added 4 commits October 1, 2026 18:23
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ar6Ahymw9LhLsnM324z5cV
Signed-off-by: Yaraslau Tamashevich <yaraslau.tamashevich@gmail.com>
CountMembers counted how many initializers an aggregate accepts by growing
the initializer list until it got rejected. That stops immediately for an
aggregate containing a member without a default constructor, since every
initializer list that does not reach that member is ill-formed, so such
types were reported as having no members.

Counting now works as follows:

- With structured binding packs (P1061, __cpp_structured_bindings >=
  202411L), the member count is read directly from the size of the pack.
  This has constant compile-time cost and also handles reference and array
  members correctly. Clang offers the feature as an extension before C++26,
  so its extension warning is silenced around that function.
- Otherwise, the smallest accepted initializer count is searched linearly,
  and from there the largest one is found by doubling and bisecting,
  replacing the previous linear recursion over a growing type pack.

A type whose members cannot be counted within MaxReflectionMemerCount now
fails with a static_assert naming the likely cause, instead of exceeding
the template instantiation depth.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ar6Ahymw9LhLsnM324z5cV
Signed-off-by: Yaraslau Tamashevich <yaraslau.tamashevich@gmail.com>
The clang and gcc jobs installed the compiler version from the matrix, but
the presets always picked the default clang++ / g++, so each matrix entry
built with the same compiler. Pass the versioned compiler explicitly.

Also:

- extend the matrix to clang 17-22 and gcc 13-16 (15 and 16 via the
  official gcc container images), so that both member counting
  implementations are covered
- build every compiler in C++20 and C++23, and C++26 where supported
- add clang-cl and macOS jobs, plus the macOS test presets they need

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ar6Ahymw9LhLsnM324z5cV
Signed-off-by: Yaraslau Tamashevich <yaraslau.tamashevich@gmail.com>
Both Windows jobs failed before compiling anything:

- The pinned vcpkg baseline was old enough that the msys2 packages it
  downloads to build Catch2 are gone from the mirrors. Bump the baseline.
- The windows-latest image now ships Visual Studio 2026, so the
  "Visual Studio 17 2022" generator named by the MSVC preset finds no
  installation. Build with Ninja from a developer environment instead,
  which works with whichever Visual Studio version the runner provides.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ar6Ahymw9LhLsnM324z5cV
Signed-off-by: Yaraslau Tamashevich <yaraslau.tamashevich@gmail.com>
@Yaraslaut
Yaraslaut force-pushed the improvement/count-members-no-default-ctor branch from c9bfa33 to 48465ef Compare October 1, 2026 16:31
@Yaraslaut
Yaraslaut merged commit 4a33204 into master Oct 1, 2026
33 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant