Date: Tue, 10 Nov 2026 19:49:30 +0200
Indeed, the current model is very consistent. The requested change is
not motivated by ideas of philosophical purity or the like, but rather
by very practical implications.
The first issue is safety. Reflection of program metadata (not involving
splicing), which by necessity happens entirely at compile time, is
always memory safe. Splicing of non-public members on the other hand is
a fundamentally unsafe operation. The access controls protect class
invariants from being invalidated by external actors, and they protect
external actors from concurrent access happening within the class.
Violating assumptions through either route leads to undefined behaviour.
A good demonstration of the fundamental unsafety of access breaking
comes from Rust. If such a feature existed in Rust, it would have to be
considered unsafe, lest the entire borrow checker be made unsound. In a
time when safety is more important than ever, C++ should not be
introducing new implicitly unsafe features.
The second issue is coupling. Allowing access to implementation
increases coupling between libraries. This has been found detrimental
time and again by other comparable programming language ecosystems. In
most cases it has been chosen to restrict access after users inevitably
abuse it. Some examples: Java (Project Jigsaw, JEP 260, JEP 396, JEP
403, ...), Go (//go:linkname directives restricted in version 1.23),
JavaScript (ES2022 introduced #private members). .NET is notable in that
they chose to go the other way and embrace access breaking. In .NET 8 a
compiler attribute called [UnsafeAccessor] was introduced for this very
purpose.
If WG21 considers access breaking an important feature, then it should
be explicit and auditable, as .NET has chosen to do. Note that
access_context::unchecked() is insufficient, because - as noted above -
access to non-public program metadata is not in itself unsafe, nor is it
likely to introduce much greater coupling than what already exists due
to type traits and ABI.
Finally, it should be understood that access breaking is not necessary
for flagship reflection use cases such as serialization, because any
such use case requires cooperation between the serializer and the class
being serialized. This is because access controls imply invariants and
given an arbitrary class, it is impossible to deduce those invariants
through reflection. Most likely that cooperation will take the form of
annotations provided by the serialization library. Given that
cooperation is necessary, it is not an undue burden for such a class to
also befriend some part of the serialization library, as libraries have
done for decades (see e.g. boost::serialization::access).
- Lauri Ojell-Vasama
On 10/11/2026 16.43, Tomasz Kamiński via SG7 wrote:
>
>
> wt., 10 lis 2026 o 15:10 Tomasz Kamiński <tomaszkam_at_[hidden]> napisał(a):
>
>
>
> sob., 7 lis 2026 o 23:38 Hana Dusíková via Ext
> <ext_at_[hidden]> napisał(a):
>
> Dear SG7 kidnapees, school-yard bullies, nerds, innocent
> bystanders, mountaineers,
>
> we are going to have an 4FA SG7 telecon this Wednesday, on zoom:
>
> https://iso.zoom.us/j/95914491492 the password is not part of
> the link, and you must do some self-reflection and type it o
> your own: [:^^_:][_]
>
> Good luck!
>
> The meeting starts and ends depending on your spatial and
> temporal location:
>
> 18:00 - 20:00 CET 🇪🇺
> 17:00 - 19:00 UTC 💂🏿♀️
> 19:00 - 21:00 EET 🗡️
> 20-00 - 22:00 MSK🪆
> 09:00am - 11:00am PST 🌁
> 10:00am - noon MST 🏔️
> noon - 2pm EST 🗽
> 02:00am - 04:00am JST 👘
> 10:30pm - 00:30am IST 🪷
> 07:00am - 09:00am HST vo🌋
>
> (it's also in the calendar)
>
> sidenote: I need a scribe! ⚠️
>
> We are going to discuss following DIS comments:
>
> * https://github.com/cplusplus/nbballot/issues/1013 "make
> results of define_*_static functions structural, so it can
> be used directly as CNTTP"
> * https://github.com/cplusplus/nbballot/issues/1006 "reflection
> of standard library entities" (mostly module related, it's
> reflection of using-declarations, which is currently
> ill-formed)
> * https://github.com/cplusplus/nbballot/issues/1005 "disallow
> obj.[: private_reflection :] splicing of private members"
> (maybe it will go directly to EWG, depending on the
> response from author)
>
> Ville, would be possible for you to provide me a more context
> here, especially to answer following question by consulting with
> Finland NB/comemnt author.
>
> I am mostly interesting in the author reasoning for providing a
> different rules for obj.*private-memeber-pointer and obj.[:
> private _reflection :].
> I see this two as parallel, as in both situation we are using
> handle representing an concrete member, and not performing it's
> lookup.
> And in rest of cpluplus the access check is consistently attached
> to lookup and not other usages, for example
> (https://godbolt.org/z/Paoh16rE1):
> class X {
> struct Y { ... };
> public:
> X foo();
>
> The return here of foo() should be 'Y' not 'X`, as otherwise the
> example fail to convey my point.
>
> };
>
> X::Y x; // ill-formed, Y is private
> decltype(std::declval<X&>().foo()) x; // OK, the name is private,
> but class not
>
> I find the current model to be very consistent with the rest of
> the language, the access check is performed when forming an reflection
> handle (^^X::Y or passing right member context to members_of), but
> afterwards no checks is performed. Without a very strong motivation,
> I would be opposed to deviating to above model.
>
>
>
> And these are all related papers, or papers proposing the fixes:
>
> * P4414R0
> <https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4414r0.html> (Ville's
> paper from mailing which proposed special context specific
> keyword)
> * P4340R0
> <https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4340r.html> (Barry's
> paper from September mailing for c++26 providing generic
> and customizable solution) (there is a newer version here:
> D4341R1
> <https://brevzin.github.io/cpp_proposals/4340_extend_cnttp_3/p4340r1.html> (contains
> wording!)
> * D4442R0
> <https://isocpp.org/files/papers/D4442R0.html> (Ville's
> paper summarizing SG7 Mattermost discussion, proposing
> future compatible way with P4340 without customization,
> only as opt-in/opt-out for structurality of types)
> * P3687R1
> <https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3687r1.html> (Dan's
> paper from Sofia which proposed way how to handle
> using-declaration, but we decided to make them ill-formed,
> in order to find a good solution later)
> * There is no paper for the splicing (the third comment)
> AFAIK, this will be discussed in EWG week later in Búzios
>
>
> I probably forgot some, so if anyone working on these please
> send them to this thread.
>
> Also meeting notes will be edited here during the meeting:
> https://docs.google.com/document/d/1SQMMIlbtahNDE70SnKMfos6Mlf2sGPo0ryg0ANWjhFU/edit?usp=sharing
>
> And I think that's all.
>
> Hana
>
> _______________________________________________
> Ext mailing list
> Ext_at_[hidden]
> Subscription: https://lists.isocpp.org/mailman/listinfo.cgi/ext
> Link to this post: http://lists.isocpp.org/ext/2026/11/28443.php
>
>
not motivated by ideas of philosophical purity or the like, but rather
by very practical implications.
The first issue is safety. Reflection of program metadata (not involving
splicing), which by necessity happens entirely at compile time, is
always memory safe. Splicing of non-public members on the other hand is
a fundamentally unsafe operation. The access controls protect class
invariants from being invalidated by external actors, and they protect
external actors from concurrent access happening within the class.
Violating assumptions through either route leads to undefined behaviour.
A good demonstration of the fundamental unsafety of access breaking
comes from Rust. If such a feature existed in Rust, it would have to be
considered unsafe, lest the entire borrow checker be made unsound. In a
time when safety is more important than ever, C++ should not be
introducing new implicitly unsafe features.
The second issue is coupling. Allowing access to implementation
increases coupling between libraries. This has been found detrimental
time and again by other comparable programming language ecosystems. In
most cases it has been chosen to restrict access after users inevitably
abuse it. Some examples: Java (Project Jigsaw, JEP 260, JEP 396, JEP
403, ...), Go (//go:linkname directives restricted in version 1.23),
JavaScript (ES2022 introduced #private members). .NET is notable in that
they chose to go the other way and embrace access breaking. In .NET 8 a
compiler attribute called [UnsafeAccessor] was introduced for this very
purpose.
If WG21 considers access breaking an important feature, then it should
be explicit and auditable, as .NET has chosen to do. Note that
access_context::unchecked() is insufficient, because - as noted above -
access to non-public program metadata is not in itself unsafe, nor is it
likely to introduce much greater coupling than what already exists due
to type traits and ABI.
Finally, it should be understood that access breaking is not necessary
for flagship reflection use cases such as serialization, because any
such use case requires cooperation between the serializer and the class
being serialized. This is because access controls imply invariants and
given an arbitrary class, it is impossible to deduce those invariants
through reflection. Most likely that cooperation will take the form of
annotations provided by the serialization library. Given that
cooperation is necessary, it is not an undue burden for such a class to
also befriend some part of the serialization library, as libraries have
done for decades (see e.g. boost::serialization::access).
- Lauri Ojell-Vasama
On 10/11/2026 16.43, Tomasz Kamiński via SG7 wrote:
>
>
> wt., 10 lis 2026 o 15:10 Tomasz Kamiński <tomaszkam_at_[hidden]> napisał(a):
>
>
>
> sob., 7 lis 2026 o 23:38 Hana Dusíková via Ext
> <ext_at_[hidden]> napisał(a):
>
> Dear SG7 kidnapees, school-yard bullies, nerds, innocent
> bystanders, mountaineers,
>
> we are going to have an 4FA SG7 telecon this Wednesday, on zoom:
>
> https://iso.zoom.us/j/95914491492 the password is not part of
> the link, and you must do some self-reflection and type it o
> your own: [:^^_:][_]
>
> Good luck!
>
> The meeting starts and ends depending on your spatial and
> temporal location:
>
> 18:00 - 20:00 CET 🇪🇺
> 17:00 - 19:00 UTC 💂🏿♀️
> 19:00 - 21:00 EET 🗡️
> 20-00 - 22:00 MSK🪆
> 09:00am - 11:00am PST 🌁
> 10:00am - noon MST 🏔️
> noon - 2pm EST 🗽
> 02:00am - 04:00am JST 👘
> 10:30pm - 00:30am IST 🪷
> 07:00am - 09:00am HST vo🌋
>
> (it's also in the calendar)
>
> sidenote: I need a scribe! ⚠️
>
> We are going to discuss following DIS comments:
>
> * https://github.com/cplusplus/nbballot/issues/1013 "make
> results of define_*_static functions structural, so it can
> be used directly as CNTTP"
> * https://github.com/cplusplus/nbballot/issues/1006 "reflection
> of standard library entities" (mostly module related, it's
> reflection of using-declarations, which is currently
> ill-formed)
> * https://github.com/cplusplus/nbballot/issues/1005 "disallow
> obj.[: private_reflection :] splicing of private members"
> (maybe it will go directly to EWG, depending on the
> response from author)
>
> Ville, would be possible for you to provide me a more context
> here, especially to answer following question by consulting with
> Finland NB/comemnt author.
>
> I am mostly interesting in the author reasoning for providing a
> different rules for obj.*private-memeber-pointer and obj.[:
> private _reflection :].
> I see this two as parallel, as in both situation we are using
> handle representing an concrete member, and not performing it's
> lookup.
> And in rest of cpluplus the access check is consistently attached
> to lookup and not other usages, for example
> (https://godbolt.org/z/Paoh16rE1):
> class X {
> struct Y { ... };
> public:
> X foo();
>
> The return here of foo() should be 'Y' not 'X`, as otherwise the
> example fail to convey my point.
>
> };
>
> X::Y x; // ill-formed, Y is private
> decltype(std::declval<X&>().foo()) x; // OK, the name is private,
> but class not
>
> I find the current model to be very consistent with the rest of
> the language, the access check is performed when forming an reflection
> handle (^^X::Y or passing right member context to members_of), but
> afterwards no checks is performed. Without a very strong motivation,
> I would be opposed to deviating to above model.
>
>
>
> And these are all related papers, or papers proposing the fixes:
>
> * P4414R0
> <https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4414r0.html> (Ville's
> paper from mailing which proposed special context specific
> keyword)
> * P4340R0
> <https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p4340r.html> (Barry's
> paper from September mailing for c++26 providing generic
> and customizable solution) (there is a newer version here:
> D4341R1
> <https://brevzin.github.io/cpp_proposals/4340_extend_cnttp_3/p4340r1.html> (contains
> wording!)
> * D4442R0
> <https://isocpp.org/files/papers/D4442R0.html> (Ville's
> paper summarizing SG7 Mattermost discussion, proposing
> future compatible way with P4340 without customization,
> only as opt-in/opt-out for structurality of types)
> * P3687R1
> <https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3687r1.html> (Dan's
> paper from Sofia which proposed way how to handle
> using-declaration, but we decided to make them ill-formed,
> in order to find a good solution later)
> * There is no paper for the splicing (the third comment)
> AFAIK, this will be discussed in EWG week later in Búzios
>
>
> I probably forgot some, so if anyone working on these please
> send them to this thread.
>
> Also meeting notes will be edited here during the meeting:
> https://docs.google.com/document/d/1SQMMIlbtahNDE70SnKMfos6Mlf2sGPo0ryg0ANWjhFU/edit?usp=sharing
>
> And I think that's all.
>
> Hana
>
> _______________________________________________
> Ext mailing list
> Ext_at_[hidden]
> Subscription: https://lists.isocpp.org/mailman/listinfo.cgi/ext
> Link to this post: http://lists.isocpp.org/ext/2026/11/28443.php
>
>
Received on 2026-11-10 17:49:42
