The posted code does not call Derived<int>::get_a()
so that template member function does not get instantiated (and there is no "access" of the private parent member to speak of).
Adding the following get_a()
call causes the same error as in the non-template case.
{
Derived<int> d;
d.get_a(); // error: 'A* Base::m_pA' is private within this context
}
[ EDIT ] The implicit instantiation of template member functions (only) when used is ruled in the C++ standard under temp.inst/4:
Unless a member of a templated class is a declared specialization, the specialization of the member is implicitly instantiated when the specialization is referenced in a context that requires the member definition to exist or if the existence of the definition of the member affects the semantics of the program;
An explicit definition of the template specialization (though not just a declaration) will cause full instantiation of all members, resulting in the same error.
extern template class Derived<int>; // explicit declaration - ok
template class Derived<int>; // explicit definition - error: 'A* Base::m_pA' is private within this context
[ EDIT #2 ] The argument was made in the comments (thanks @Jarod42) that the given code falls into the "ill-formed, no diagnostic required" category, meaning the compiler is allowed (though not required) to reject it on grounds that no possible (complete) instantiation of the class template Derived<T>
can exist because of the private
member access in get_a()
even if the member function is never used.
This interpretation is based on the following section of temp.res.general/6.1:
The program is ill-formed, no diagnostic required, if:
- no valid specialization can be generated for a template or a substatement of a constexpr if statement within a template and the template is not instantiated, or [...]
If "valid specialization can be generated" is taken to mean a complete explicit specialization of the entire template class, then the given code snippet is indeed "ill-formed NDR".
If, however, "valid specialization" is understood to cover implicit specializations of the template class with (only) the required members as defined in temp.inst/4 quoted earlier, then the given code snippet does not fall under "ill-formed NDR" because get_a()
is never instantiated (per temp.inst/11: "an implementation shall not implicitly instantiate a function template, a variable template, a member template, a non-virtual member function, a member class or static data member of a templated class, or a substatement of a constexpr if statement, unless such instantiation is required").
The linked demo shows that gcc
takes the latter interpretation, while clang
the former.
In either case, the answer stands that if the template is not rejected upfront as "ill-formed NDR" because of the no-valid-specializations-can-exist clause, then it will compile and work fine as long as get_a()
does not get instantiated, either implicitly by direct reference, or by an explicit specialization of the template class.