C++ Logo

std-proposals

Advanced search

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

From: Mital Ashok <mital_at_[hidden]>
Date: Fri, 29 May 2026 05:05:33 +0100
On Thu, 28 May 2026, 16:51 Máté Ték via Std-Proposals, <
std-proposals_at_[hidden]> wrote:

>
> The real issue with classic PEMs IMO is that they live in the same "name
> space" as the "first-class class members".
> This is what generates the friction with overload resolution/ODR.
> So I thought, let's give them a "name space" within the class they're
> extending!
> After some fooling around with various syntaxes, here's my strongest
> candidate:
>
> /// MyClass.hpp
> class MyClass {
> public:
> void Foo(int);
> void Bar(int);
> private:
> int mySecret;
> };
>
> /// MyClass.cpp
> namespace {
> private extension MyClass::impl {
> void FooBar(int i) { mySecret += i; }
> // virtual void Gaz(); ERROR: extension member function cannot be
> virtual
> // int otherSecret; ERROR: extension cannot have non-static
> data members
> static int otherSecret; // OK, why not?
> };
> // I could have defined FooBar out-of-line like so:
> void MyClass::impl::FooBar(int i) { mySecret += i; }
> }
> void MyClass::Foo(int i) { impl::FooBar(i + 1); }
> void MyClass::Bar(int i) { impl::FooBar(i * 2); }
> // static void SomeFunction(MyClass& x) { x.impl::FooBar(42); } ERROR:
> class interface extension MyClass::impl is private
>
> Thus we eliminated the overload resolution/ODR concerns.
> It is now very clear that PEMs are not "first-class" members of the class.
> The interface of the class, and therefore its "identity" is undisputed and
> unfractured.
>

A similar thing can be implemented with existing language features:

// header
class X {
private:
  // ...
  struct impl;
  friend impl;
public:
  int public_interface();
};

// source
struct X::impl {
  static int helper(X& self) {
    // ...
  }
};
int X::public_interface() {
  return impl::helper(*this);
}


This loses the easier syntax of an implicit object argument and has
external linkage (though you can work around that with `namespace detail {
namespace { struct X_helper; } } ` and `friend detail::X_helper;`), but is
implementable today without exposing too much in the header.

Encapsulation is not broken.
> Interface extensions naturally follow the good ol' class syntax.
>

Encapsulation/access control does seem broken. This could allow private
member access in any translation unit by just defining an extension. This
could be fixed by requiring a declaration of the extension but that is
closer to something like Java interfaces as opposed to Rust impl/traits

>

Received on 2026-05-29 04:05:51