C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Translation-unit-local functions that access private class fields

From: Máté Ték <eppenpontaz_at_[hidden]>
Date: Tue, 28 Apr 2026 20:07:55 +0200
I didn't mean 'breaking change' literally. I was only trying to make a
point. A new feature that immediately applies to all existing classes
sounds a bit unnerving to me. Even if it should not break anything in
theory. I might just be unnecessary cautious.

Having said that, I still prefer my proposed syntax for multiple reasons.

Here's a quote from "The C++ Programming Language" (Fourth Edition) from
Bjarne:

There are several benefits to be obtained from restricting access to a data
> structure to an explicitly declared list of functions. For example, any
> error causing a Date to take on an illegal value (for example, December 36,
> 2016) must be caused by code in a member function. This implies that the
> first stage of debugging – localization – is completed before the program
> is even run.

[...]

Another advantage is that a potential user need examine only the
> definitions of the member functions in order to learn to use a class.


Personally I would be delighted to see the 'bouquet of private methods'
listed explicitly on the implementation side too.
Mainly because I, and a lot of other C++ engineers out there, am working
with someone else's code. Even 'my own modules' (codes I am responsible
for) I have written less than 0.1% of the code. Therefore, in my case, all
arguments for a tidy public interface also apply to the private interface.
Especially if that interface consists of > 30 methods.
It would force us to be somewhat tidy, and I think that's a good thing.

It would also solve the issue of predeclaration of these methods.

It wouldn't require repeating the 'private' keyword and the class name:

private void MyClass::foo();
private void MyClass::bar();
private void MyClass::baz();

vs

class [[implementation]] MyClass {
private:
    void foo();
    void bar();
    void baz();
};

This would also make the transition easier for existing code.

I discussed this with a colleague today, and he said (to my proposed
syntax) 'why restrict ourselves to private member functions', and I think
he's onto something. My proposal allows for this without breaking
encapsulation:

// Header:
class [[exposition]] MyClass {
public:
    MyClass(Precious&);
    void Foo();
};

// .cpp
class [[implementation]] MyClass {
public:
    // Only visible in this translation unit:
    MyClass();
    std::uint64_t MyHash() const;
};

// Needs hashable type, creates instance with std::make_shared
auto prototypeObj = ::RegisterMyPrototype<MyClass>();

Now whether this is an antipattern or a legitimate use case is up for
debate.

Just some things to consider. I mean no competition or criticism. I am just
trying to explore the solution space.
I agree with the core idea 100%.

Sincerely,
Matthew


On Tue, 28 Apr 2026 at 12:10, Rhidian De Wit <rhidiandewit_at_[hidden]> wrote:

> 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
>>
>

Received on 2026-04-28 18:08:10