Hi André,
I think you got the point itself.
As Thiago pointed out, it does not have to be necessarily templates.
It probably is enough, if the member function is defined inside the header file, e.g. directly within the declaration of the class or marked as inline.
Then overload resolution could differ even for calls (to private member functions) within the class.
Currently there are already possible ODR violations for calls outside the class, if a different (e.g. free) function is called.
Internal linkage, which should protect the class encapsulation could give the wrong picture about those private extension functions. Shifting the image from unique and declared upfront per class to declared per TU and not only private in the class, but also exclusive to the TU.
The mental picture should still be that all private functions are clearly separate from each other (even over several TUs). And if they have the same name/signature, then they should not be called by any of the functions defined in a header file: templates, functions defined in the declaration and inlined functions.
-----Ursprüngliche Nachricht-----
Von: André Offringa via Std-Proposals <std-proposals@lists.isocpp.org>
Gesendet: Mi 29.04.2026 08:59
Betreff: Re: [std-proposals] Translation-unit-local functions that access private class fields
An: std-proposals@lists.isocpp.org;
CC: André Offringa <offringa@gmail.com>;
On 4/29/26 12:40 AM, Thiago Macieira via Std-Proposals wrote:
> On Tuesday, 28 April 2026 15:12:26 Pacific Daylight Time Sebastian Wittmeier
> via Std-Proposals wrote:
>> Could template member functions, declared in the class together with private
>> extension functions, which change overload resolution, be a small issue?
> Yes, that could cause an ODR violation. You don't need templates for that
> either. Plus, you can get violations without overloads, by using requires
> clauses.
Is the following an example of what you mean with ODR violation?
== Header ==
template<typename T>
class Foo {
public:
Foo() {
A(T()); // dependent lookup, overload resolved at instantiation
}
private:
void A(double);
// void A(int); -> not declared, extended later
}
// If Foo instantiated here -> A(int) does not participate
== cpp ==
private void Foo::A(int) {
}
// If Foo instantiated here -> A(int) does participate
So if in one translation unit Foo is instantiated without seeing A(int)
and in another
Foo is instantiated with seeing A(int), it would be ill-formed (IFNDR).
If you were thinking of a different problem, could you give an example?
I think this problem is similar as that is already the case with free
functions, isn't it?
Though maybe this trap is slightly more easy to trigger... not sure. At
the very least,
this problem didn't exist for class members before and now it does, so I
think that's
worthwhile to mention in the proposal. Good points, thanks!
Regards,
André
--
Std-Proposals mailing list
Std-Proposals@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals