Date: Tue, 28 Apr 2026 10:10:37 +0200
The original proposal isn’t breaking though. It suggests to re-use the
private keyword in function declarations, something that is currently not
allowed.
I don’t think it’s a good idea to make every language change via
attributes, as it will become overly saturated, while in this case re-using
the private keyword makes syntactically and meaning-wise sense.
A private extension function is a “private” function, in essence very
similar to a friend function without the requirement to pollute the header
file
Rhidian De Wit
Software Engineer - Barco
Op di 28 apr 2026 om 10:52 schreef Máté Ték via Std-Proposals <
std-proposals_at_[hidden]>
> Hi,
>
> I am late to this discussion, but this issue is very fascinating.
>
> Disclaimer: I can't type this mail, I am on my way to work, so I'll use
> ChatGPT voice-to-text to phrase my thoughts, so if it feels AI-generated,
> it's because it is, but they are very much my thoughts. Also keep in mind
> that I am no authority here, I am just a regular C++ enthusiast, and this
> is just my opinion.
>
> I think to understand the deeper issue here, we have to transcend C++ for
> a bit and be a bit philosophical about classes.
> A class is essentially a collection of data members and member functions.
> Each member—both functions and variables—has a visibility: public,
> protected, or private.
> The issue is that we need multiple different renditions of this abstract
> class. In a way, just like a person presents different aspects of
> themselves depending on context, a class also has different “faces.” It is
> still the same entity, but we expose different parts of it depending on who
> is interacting with it.
> In software, this means the same class must have a public exposition for
> its users. They need to see the public (and possibly protected) members so
> they can use them. They also need to see all data members—including private
> ones—because those contribute to the physical memory layout of the class.
> This is already a point of friction: private members are not accessible,
> yet they must still be visible for layout reasons. That’s simply a
> consequence of how physical computers work, and we must accept that.
> But we should ask: is this also true for private member functions? It
> seems the answer is no. They do not seem to affect layout, so they don’t
> strictly need to be declared in the header. In that sense, the proposal is
> well-founded.
> If we continue this idea of multiple renditions, we arrive at the need for:
> - a public exposition of the class, and
> - a rendition for the implementation.
> A naïve approach—having two completely separate interface
> declarations—would require duplicating all public members and data members
> in two places. That is clearly unacceptable, because any change to the
> public interface would need to be made twice.
> A more viable approach is to let the implementation-side declaration
> specify only the delta—i.e., what is added on top of the public interface.
>
> Now, one open question I have is about private virtual functions. Even
> though they don’t affect the object layout directly, they do contribute
> entries to the vtable. I’m not sure whether they can be omitted from the
> exposition without issues. I’d appreciate input from someone with deeper
> expertise in this area.
>
> From a syntax perspective, we should also be careful. This feature would
> need to coexist with existing code, and it could be confusing if a reader
> suddenly sees private member functions “missing” from the class definition
> and moved elsewhere.
> For that reason, I think a clear, opt-in mechanism would be important—for
> both humans and tooling.
> One possible direction would be to introduce new standard attributes. For
> example:
>
> // header
> class [[exposition]] MyClass {
> public:
> void foo();
>
> private:
> int data;
> };
>
> // .cpp
> class [[implementation]] MyClass {
> private:
> void helper(); // only visible here
> };
>
> This makes the intent explicit:
> the header provides the exposition,
> the source file provides the implementation extension.
> It would be immediately clear to readers that the class opts into this
> model, and IDEs could also take advantage of this structure.
> From a tooling and language perspective, this would require compiler and
> linker support. The rule could be that all translation units see the same
> public exposition of the class, just like today. However, if this opt-in
> feature is used, there must be exactly one implementation definition of the
> class. If it is missing, that would be a link-time error; if multiple
> implementations exist, that would also be a linker error. This is
> completely analogous to how ordinary functions behave, so it seems
> realistically supportable.
> This model should also work naturally with modules: only the
> [[exposition]] interface would be exported, while the [[implementation]]
> part can remain internal to the module.
>
> IMO this sould be a purely optional, opt-in feature—more of an extension
> than a 'breaking' language change.
>
> Sincerely,
> Matthew
>
> Steve Weinrich via Std-Proposals <std-proposals_at_[hidden]> ezt
> írta (időpont: 2026. ápr. 28., Ke 6:50):
>
>> Hi André,
>>
>> IMHO, the only way to achieve what you are looking for (in something of a
>> secure manner) is to invent a new rule for the compiler. Something like,
>> “One of the constructors for a class may be marked with a new attribute
>> [[KEY]]. All methods marked with the [[FRIEND class-name]] attribute
>> within the same compilation unit as the class constructor containing the
>> [[KEY]] attribute will be granted friend access to the specified class.”
>> Note that I am using attributes here, but they could not be used like this
>> as the code must be able to be compiled without support for particular
>> attributes. This is just presenting a notion.
>>
>> I hope that helps.
>>
>> Chers,
>> Steve
>>
>>
>>
>> *From:* Std-Proposals <std-proposals-bounces_at_[hidden]> *On
>> Behalf Of *André Offringa via Std-Proposals
>> *Sent:* Monday, April 27, 2026 1:21 AM
>> *To:* std-proposals_at_[hidden]
>> *Cc:* André Offringa <offringa_at_[hidden]>
>> *Subject:* Re: [std-proposals] Translation-unit-local functions that
>> access private class fields
>>
>>
>>
>> Hi Steve,
>>
>> Thanks for the feedback. You're suggesting helper friend classes as an
>> alternative, but there are some issues with a helper friend class to enable
>> translation-unit-local functions. First of all, to make the functions
>> translation-unit-local, it must be placed in an anonymous namespace. To do
>> this, it must be done so before the befriending, so something like this:
>>
>> == header file ==
>>
>> namespace {
>> struct FooFriend;
>> }
>>
>> class Foo {
>> int a;
>> friend FooFriend;
>> };
>>
>> == cpp file ==
>>
>> namespace {
>> struct FooFriend {
>> static void SetA(Foo& foo) {
>> foo.a = 3;
>> }
>> };
>> }
>>
>> I think this is an awkward construct. The Google C++ style explicitly
>> forbids this, as it doesn't allow unnamed namespaces in header files. The
>> SetA() function is also now publicly available, and even though that is
>> limited to a single translation unit, it is still easy to accidentally
>> break a class invariant in this way. The classname of FooFriend is leaked
>> out of the scope of the unit file (style guides often mandate to put it in
>> yet another subnamespace like 'details' in that case). Finally, the syntax
>> of the call and use of private variables is more verbose. Compare it to:
>>
>> == header file ==
>>
>> class Foo {
>> int a;
>> };
>>
>> == cpp file ==
>>
>> private Foo::SetA() {
>> a = 3;
>> }
>>
>>
>>
>> So, while there are alternatives for private functions, I don't think the
>> friend classes are really a solution for the issue that the proposal tries
>> to solve.
>>
>> Kind regards,
>> André
>>
>> On 4/26/26 11:05 PM, Steve Weinrich via Std-Proposals wrote:
>>
>> This is purely subjective, but I don't find that a single line, "friend
>> class Helper;" is clutter. It can be put at the very bottom of the class.
>> It gives Helper full access for whatever purpose. No committee required!
>>
>>
>>
>> Cheers,
>>
>> Steve
>>
>>
>>
>> On Sun, Apr 26, 2026, 00:17 André Offringa via Std-Proposals <
>> std-proposals_at_[hidden]> wrote:
>>
>> On 4/25/26 10:56 PM, Steve Weinrich via Std-Proposals wrote:
>>
>> I may have missed something, but one can declare:
>>
>>
>>
>> class Foo
>>
>> {
>>
>> friend class Helper;
>>
>>
>>
>> friend void FooHelper (Foo *);
>>
>> };
>>
>>
>>
>> Both the class Helper and the function FooHelper() can access all private
>> members of Foo. Thus, only the names and/or the function signature is
>> declared in the interface.
>>
>>
>>
>> What I'm trying to solve:
>>
>> - Wen using friend declarations, these clutters the class with
>> implementation details that do not affect the layout of the class.
>>
>> - For FooHelper(), it would require the return and parameters types to be
>> available at the place of the friend declaration, creating extra
>> dependencies. Your example takes only Foo*, but I think it's common for a
>> helper function to use other parameters (and/or have a return value), which
>> causes the dependencies.
>>
>> Regards,
>> André
>>
>>
>>
>>
>>
>> On Sat, Apr 25, 2026, 14:46 André Offringa via Std-Proposals <
>> std-proposals_at_[hidden]> wrote:
>>
>> Hi all,
>>
>> I was wondering what people think of the following idea. The problem I'm
>> trying to address is that if we want to introduce a helper method for a
>> class, we have to declare this helper function in the class, e.g. assume
>> this situation:
>>
>> == Header file: ==
>>
>> class Foo {
>> public:
>> void A();
>>
>> private:
>> void Helper();
>>
>> int value_;
>> };
>>
>> == Unit file: ==
>>
>> void Foo::A() {
>> ...
>> Helper();
>> ...
>> }
>>
>> void Foo::Helper() {
>> ...
>> value_ = ...;
>> ...
>> }
>>
>> I think it would be useful if there would be a way to skip the
>> declaration of the Helper method inside the class (in the header file),
>> and make it translation local just like a static function or function
>> inside an anonymous namespace would be. From the compiler's point of
>> view, it could then act as a translation-unit-local function, except
>> with the possibility to access (private) class fields.
>>
>> The benefit is that the method is no longer part of the "interface" of
>> the class, and this is useful because it is, after all, an
>> implementation detail of the class. This makes it also no longer
>> necessary to have the parameter types and return value type declared in
>> the header file, which decreases dependencies between files.
>>
>> An example of how this could look like, could be to use the keyword
>> 'private' and let it act as an identifier for declaring such a function,
>> e.g.:
>>
>> == Header file: ==
>>
>> class Foo {
>> public:
>> void A();
>>
>> private:
>> int value_;
>> }
>>
>> == Unit file: ==
>>
>> private void Foo::Helper() {
>> ...
>> value_ = ...;
>> ...
>> }
>>
>> void Foo::A() {
>> ...
>> Helper();
>> ...
>> }
>>
>> Of course the syntax is open for discussion. The idea is that Helper()
>> is now a private translation-unit-local function that receives the
>> 'this' pointer and access to private fields. The function itself acts in
>> name lookup as a free function, to avoid participating in member lookup,
>> but is only visible inside class member functions or other private
>> translation-unit-local functions, and is not accessible outside of that.
>> This makes it somewhat between a member function and a free function.
>> With such an approach, it can not be used to access private fields from
>> a scope that does not allow access to those fields. Hence, the class
>> data remains encapsulated. It should not modify the layout of the class
>> and not change its ABI. There are more details to think through.
>>
>> Thinking of alternatives, another direction to solve this would be to
>> change the standard such that friend functions can be declared as friend
>> outside of the class definition, instead of by introducing a function
>> with special visibility rules. They would then behave as normal
>> functions, which simplify some details. This makes private data too
>> widely usable, so I don't see a good solution in that direction.
>>
>> Syntax aside, the problem I'm trying to solve is to have a function that:
>> - has access to private members
>> - is defined only in the unit file
>> - does not require any declaration in the header
>> - does not become part of the class interface
>>
>> I think the best existing alternative for this situation is to declare a
>> static free function in the unit file that takes as parameter the class
>> members it needs. In complex situations, this is not as nice. In pimpl
>> implementations it is a reasonable solution, but a pimpl pattern is not
>> always desired.
>>
>> I'm curious to hear what people think about the idea of private
>> translation-unit-local functions.
>>
>> Kind regards,
>> André Offringa
>>
>> --
>> Std-Proposals mailing list
>> Std-Proposals_at_[hidden]
>> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>>
>>
>>
>> --
>> Std-Proposals mailing list
>> Std-Proposals_at_[hidden]
>> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>>
>>
>>
>> --
>> Std-Proposals mailing list
>> Std-Proposals_at_[hidden]
>> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>>
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
private keyword in function declarations, something that is currently not
allowed.
I don’t think it’s a good idea to make every language change via
attributes, as it will become overly saturated, while in this case re-using
the private keyword makes syntactically and meaning-wise sense.
A private extension function is a “private” function, in essence very
similar to a friend function without the requirement to pollute the header
file
Rhidian De Wit
Software Engineer - Barco
Op di 28 apr 2026 om 10:52 schreef Máté Ték via Std-Proposals <
std-proposals_at_[hidden]>
> Hi,
>
> I am late to this discussion, but this issue is very fascinating.
>
> Disclaimer: I can't type this mail, I am on my way to work, so I'll use
> ChatGPT voice-to-text to phrase my thoughts, so if it feels AI-generated,
> it's because it is, but they are very much my thoughts. Also keep in mind
> that I am no authority here, I am just a regular C++ enthusiast, and this
> is just my opinion.
>
> I think to understand the deeper issue here, we have to transcend C++ for
> a bit and be a bit philosophical about classes.
> A class is essentially a collection of data members and member functions.
> Each member—both functions and variables—has a visibility: public,
> protected, or private.
> The issue is that we need multiple different renditions of this abstract
> class. In a way, just like a person presents different aspects of
> themselves depending on context, a class also has different “faces.” It is
> still the same entity, but we expose different parts of it depending on who
> is interacting with it.
> In software, this means the same class must have a public exposition for
> its users. They need to see the public (and possibly protected) members so
> they can use them. They also need to see all data members—including private
> ones—because those contribute to the physical memory layout of the class.
> This is already a point of friction: private members are not accessible,
> yet they must still be visible for layout reasons. That’s simply a
> consequence of how physical computers work, and we must accept that.
> But we should ask: is this also true for private member functions? It
> seems the answer is no. They do not seem to affect layout, so they don’t
> strictly need to be declared in the header. In that sense, the proposal is
> well-founded.
> If we continue this idea of multiple renditions, we arrive at the need for:
> - a public exposition of the class, and
> - a rendition for the implementation.
> A naïve approach—having two completely separate interface
> declarations—would require duplicating all public members and data members
> in two places. That is clearly unacceptable, because any change to the
> public interface would need to be made twice.
> A more viable approach is to let the implementation-side declaration
> specify only the delta—i.e., what is added on top of the public interface.
>
> Now, one open question I have is about private virtual functions. Even
> though they don’t affect the object layout directly, they do contribute
> entries to the vtable. I’m not sure whether they can be omitted from the
> exposition without issues. I’d appreciate input from someone with deeper
> expertise in this area.
>
> From a syntax perspective, we should also be careful. This feature would
> need to coexist with existing code, and it could be confusing if a reader
> suddenly sees private member functions “missing” from the class definition
> and moved elsewhere.
> For that reason, I think a clear, opt-in mechanism would be important—for
> both humans and tooling.
> One possible direction would be to introduce new standard attributes. For
> example:
>
> // header
> class [[exposition]] MyClass {
> public:
> void foo();
>
> private:
> int data;
> };
>
> // .cpp
> class [[implementation]] MyClass {
> private:
> void helper(); // only visible here
> };
>
> This makes the intent explicit:
> the header provides the exposition,
> the source file provides the implementation extension.
> It would be immediately clear to readers that the class opts into this
> model, and IDEs could also take advantage of this structure.
> From a tooling and language perspective, this would require compiler and
> linker support. The rule could be that all translation units see the same
> public exposition of the class, just like today. However, if this opt-in
> feature is used, there must be exactly one implementation definition of the
> class. If it is missing, that would be a link-time error; if multiple
> implementations exist, that would also be a linker error. This is
> completely analogous to how ordinary functions behave, so it seems
> realistically supportable.
> This model should also work naturally with modules: only the
> [[exposition]] interface would be exported, while the [[implementation]]
> part can remain internal to the module.
>
> IMO this sould be a purely optional, opt-in feature—more of an extension
> than a 'breaking' language change.
>
> Sincerely,
> Matthew
>
> Steve Weinrich via Std-Proposals <std-proposals_at_[hidden]> ezt
> írta (időpont: 2026. ápr. 28., Ke 6:50):
>
>> Hi André,
>>
>> IMHO, the only way to achieve what you are looking for (in something of a
>> secure manner) is to invent a new rule for the compiler. Something like,
>> “One of the constructors for a class may be marked with a new attribute
>> [[KEY]]. All methods marked with the [[FRIEND class-name]] attribute
>> within the same compilation unit as the class constructor containing the
>> [[KEY]] attribute will be granted friend access to the specified class.”
>> Note that I am using attributes here, but they could not be used like this
>> as the code must be able to be compiled without support for particular
>> attributes. This is just presenting a notion.
>>
>> I hope that helps.
>>
>> Chers,
>> Steve
>>
>>
>>
>> *From:* Std-Proposals <std-proposals-bounces_at_[hidden]> *On
>> Behalf Of *André Offringa via Std-Proposals
>> *Sent:* Monday, April 27, 2026 1:21 AM
>> *To:* std-proposals_at_[hidden]
>> *Cc:* André Offringa <offringa_at_[hidden]>
>> *Subject:* Re: [std-proposals] Translation-unit-local functions that
>> access private class fields
>>
>>
>>
>> Hi Steve,
>>
>> Thanks for the feedback. You're suggesting helper friend classes as an
>> alternative, but there are some issues with a helper friend class to enable
>> translation-unit-local functions. First of all, to make the functions
>> translation-unit-local, it must be placed in an anonymous namespace. To do
>> this, it must be done so before the befriending, so something like this:
>>
>> == header file ==
>>
>> namespace {
>> struct FooFriend;
>> }
>>
>> class Foo {
>> int a;
>> friend FooFriend;
>> };
>>
>> == cpp file ==
>>
>> namespace {
>> struct FooFriend {
>> static void SetA(Foo& foo) {
>> foo.a = 3;
>> }
>> };
>> }
>>
>> I think this is an awkward construct. The Google C++ style explicitly
>> forbids this, as it doesn't allow unnamed namespaces in header files. The
>> SetA() function is also now publicly available, and even though that is
>> limited to a single translation unit, it is still easy to accidentally
>> break a class invariant in this way. The classname of FooFriend is leaked
>> out of the scope of the unit file (style guides often mandate to put it in
>> yet another subnamespace like 'details' in that case). Finally, the syntax
>> of the call and use of private variables is more verbose. Compare it to:
>>
>> == header file ==
>>
>> class Foo {
>> int a;
>> };
>>
>> == cpp file ==
>>
>> private Foo::SetA() {
>> a = 3;
>> }
>>
>>
>>
>> So, while there are alternatives for private functions, I don't think the
>> friend classes are really a solution for the issue that the proposal tries
>> to solve.
>>
>> Kind regards,
>> André
>>
>> On 4/26/26 11:05 PM, Steve Weinrich via Std-Proposals wrote:
>>
>> This is purely subjective, but I don't find that a single line, "friend
>> class Helper;" is clutter. It can be put at the very bottom of the class.
>> It gives Helper full access for whatever purpose. No committee required!
>>
>>
>>
>> Cheers,
>>
>> Steve
>>
>>
>>
>> On Sun, Apr 26, 2026, 00:17 André Offringa via Std-Proposals <
>> std-proposals_at_[hidden]> wrote:
>>
>> On 4/25/26 10:56 PM, Steve Weinrich via Std-Proposals wrote:
>>
>> I may have missed something, but one can declare:
>>
>>
>>
>> class Foo
>>
>> {
>>
>> friend class Helper;
>>
>>
>>
>> friend void FooHelper (Foo *);
>>
>> };
>>
>>
>>
>> Both the class Helper and the function FooHelper() can access all private
>> members of Foo. Thus, only the names and/or the function signature is
>> declared in the interface.
>>
>>
>>
>> What I'm trying to solve:
>>
>> - Wen using friend declarations, these clutters the class with
>> implementation details that do not affect the layout of the class.
>>
>> - For FooHelper(), it would require the return and parameters types to be
>> available at the place of the friend declaration, creating extra
>> dependencies. Your example takes only Foo*, but I think it's common for a
>> helper function to use other parameters (and/or have a return value), which
>> causes the dependencies.
>>
>> Regards,
>> André
>>
>>
>>
>>
>>
>> On Sat, Apr 25, 2026, 14:46 André Offringa via Std-Proposals <
>> std-proposals_at_[hidden]> wrote:
>>
>> Hi all,
>>
>> I was wondering what people think of the following idea. The problem I'm
>> trying to address is that if we want to introduce a helper method for a
>> class, we have to declare this helper function in the class, e.g. assume
>> this situation:
>>
>> == Header file: ==
>>
>> class Foo {
>> public:
>> void A();
>>
>> private:
>> void Helper();
>>
>> int value_;
>> };
>>
>> == Unit file: ==
>>
>> void Foo::A() {
>> ...
>> Helper();
>> ...
>> }
>>
>> void Foo::Helper() {
>> ...
>> value_ = ...;
>> ...
>> }
>>
>> I think it would be useful if there would be a way to skip the
>> declaration of the Helper method inside the class (in the header file),
>> and make it translation local just like a static function or function
>> inside an anonymous namespace would be. From the compiler's point of
>> view, it could then act as a translation-unit-local function, except
>> with the possibility to access (private) class fields.
>>
>> The benefit is that the method is no longer part of the "interface" of
>> the class, and this is useful because it is, after all, an
>> implementation detail of the class. This makes it also no longer
>> necessary to have the parameter types and return value type declared in
>> the header file, which decreases dependencies between files.
>>
>> An example of how this could look like, could be to use the keyword
>> 'private' and let it act as an identifier for declaring such a function,
>> e.g.:
>>
>> == Header file: ==
>>
>> class Foo {
>> public:
>> void A();
>>
>> private:
>> int value_;
>> }
>>
>> == Unit file: ==
>>
>> private void Foo::Helper() {
>> ...
>> value_ = ...;
>> ...
>> }
>>
>> void Foo::A() {
>> ...
>> Helper();
>> ...
>> }
>>
>> Of course the syntax is open for discussion. The idea is that Helper()
>> is now a private translation-unit-local function that receives the
>> 'this' pointer and access to private fields. The function itself acts in
>> name lookup as a free function, to avoid participating in member lookup,
>> but is only visible inside class member functions or other private
>> translation-unit-local functions, and is not accessible outside of that.
>> This makes it somewhat between a member function and a free function.
>> With such an approach, it can not be used to access private fields from
>> a scope that does not allow access to those fields. Hence, the class
>> data remains encapsulated. It should not modify the layout of the class
>> and not change its ABI. There are more details to think through.
>>
>> Thinking of alternatives, another direction to solve this would be to
>> change the standard such that friend functions can be declared as friend
>> outside of the class definition, instead of by introducing a function
>> with special visibility rules. They would then behave as normal
>> functions, which simplify some details. This makes private data too
>> widely usable, so I don't see a good solution in that direction.
>>
>> Syntax aside, the problem I'm trying to solve is to have a function that:
>> - has access to private members
>> - is defined only in the unit file
>> - does not require any declaration in the header
>> - does not become part of the class interface
>>
>> I think the best existing alternative for this situation is to declare a
>> static free function in the unit file that takes as parameter the class
>> members it needs. In complex situations, this is not as nice. In pimpl
>> implementations it is a reasonable solution, but a pimpl pattern is not
>> always desired.
>>
>> I'm curious to hear what people think about the idea of private
>> translation-unit-local functions.
>>
>> Kind regards,
>> André Offringa
>>
>> --
>> Std-Proposals mailing list
>> Std-Proposals_at_[hidden]
>> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>>
>>
>>
>> --
>> Std-Proposals mailing list
>> Std-Proposals_at_[hidden]
>> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>>
>>
>>
>> --
>> Std-Proposals mailing list
>> Std-Proposals_at_[hidden]
>> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>>
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
Received on 2026-04-28 10:10:52
