Allow a trivially copyable type to opt out of the byte copy - #196
Merged
Conversation
The specialisations of Serialise are selected by conditions assumed to be mutually exclusive, so a type that satisfies two of them makes Serialise<T> ambiguous rather than preferring one. That makes the trivially copyable specialisation unreachable to opt out of: a code generator emitting plain structs of scalars cannot supply the encoding and type identity those messages carry, because its partial specialisation ties with the byte copy and neither is more specialised than the other. A full specialisation would win outright, but that is one specialisation per type rather than one covering everything a generator emits. Route the condition through a serialise_trivially trait so it can be specialised to false. The second parameter is an SFINAE slot, so a family of types can be opted out with a single partial specialisation. The default is std::is_trivially_copyable, so behaviour is unchanged for every type that does not opt out. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
TrentHouliston
force-pushed
the
houliston/serialise-trivially-optout
branch
from
August 13, 2026 00:13
29d6894 to
4253210
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🤖 Filed on behalf of @TrentHouliston by an agent.
The problem
Serialise<T, Check>'s specialisations are selected by conditions that are assumed to be mutually exclusive. A type that satisfies two of them doesn't prefer one — it makesSerialise<T>ambiguous. That leaves the trivially copyable specialisation with no way to opt out of.The motivating case is a code generator whose message classes are plain structs of scalars. They are trivially copyable, but they carry their own wire format and their own type identity (a hash over the schema's fully qualified name, shared with peers on the other end of the wire). The byte copy bypasses both: it would send the object representation, and
hash()would identify the type by its demangled C++ name.The generator wants one partial specialisation covering everything it emits:
which ties with
Neither is more specialised than the other, so it's ill-formed:
A full explicit specialisation does win outright, so the workaround is one specialisation per type — which defeats the point when the set of types is whatever the generator emitted.
The change
Route the condition through a trait that can be specialised:
The second parameter is an SFINAE slot, so a family of types is opted out with a single partial specialisation rather than one per type. The container specialisation goes through the same trait, so a container of opted-out elements stops claiming the byte copy too.
The default is
std::is_trivially_copyable, so nothing changes for any type that does not opt out.Tests
tests/tests/util/serialise/serialise_trivially.cppis new. It sets up exactly the shape above — a trivially copyable type, a trait marking the family, a partial specialisation ofSerialise— and asserts the type's own wire format and hash are used, plus that a type which has not opted out still gets the byte copy.It does not compile before this change, and passes after it.
The existing
serialise.cpptests are unchanged and still pass (60 assertions, 6 cases).🤖 Generated with Claude Code