This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 117a. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.
2025-05-24
According to 11.8.5 [class.protected] paragraph 1, except when forming a pointer to member,
All other accesses involve a (possibly implicit) object expression (7.6.1.5 [expr.ref]).
It is not clear that this is strictly true for the invocation of a base class constructor from a mem-initializer. A wording tweak may be advisable.
Proposed resolution (March, 2025):
Change in 11.8.5 [class.protected] paragraph 1 as follows and move the example to a separate numbered paragraph:
An additional access check beyond those described earlier in 11.8 [class.access] is applied when a non-static data member or non-static member function is a protected member of its naming class (11.8.3 [class.access.base]). [ Footnote: ... ] As described earlier, access to a protected member is granted because the reference occurs in a friend or direct member of some class C. If the access is to form a pointer to member (7.6.2.2 [expr.unary.op]), the nested-name-specifier shall denote C or a class derived from C. Otherwise, if the member is a constructor, either C shall be the naming class or the access shall be the constructor call for a base class subobject of C performed by a constructor of C as described in 11.9.3 [class.base.init]. All other accesses involve a (possibly implicit) object expression (7.6.1.5 [expr.ref]).
In this caseUnless the access is an implicit destructor call for a base class subobject by a destructor of C (11.4.7 [class.dtor]), the class of the object expression shall be C or a class derived from C.[Example 1 :
class B { protected: int i; static int j; B(int = 0); ~B(); }; class D1 : public B { D1() : B(1) { // OK B b(*this); // error: destructor of B is protected } ~D1() = default; // OK };... -- end example ]