This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 115d. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2024-10-26


401. When is access for template parameter default arguments checked?

Section: 13.2  [temp.param]     Status: CD1     Submitter: Steve Adamczyk     Date: 27 Jan 2003

[Voted into WP at October 2005 meeting.]

Is the following well-formed?

  class policy {};
  class policy_interface {};
  template <class POLICY_INTERFACE>
  class aph {
  protected:
    typedef POLICY_INTERFACE PI;
  };
  template <class POLICY, class BASE, class PI = typename BASE::PI>
  class ConcretePolicyHolder : public BASE, protected POLICY
  {};
  ConcretePolicyHolder < policy , aph < policy_interface > > foo;
  void xx() { }

The issue is whether the access to the default argument type BASE::PI is checked before or after it is known that BASE is a base class of the template. To some extent, one needs to develop the list of template arguments (and therefore evaluate the default argument) before one can instantiate the template, and one does not know what base classes the template has until it has been instantiated.

Notes from April 2003 meeting:

Shortened example:

  class B {
  protected:
    typedef int A;
  };
  template<class T, class U = typename T::A>
  class X : public T
  { };

The convincing argument here is that if we had only the declaration of the template (including the default argument), we would expect it to be usable in exactly the same way as the version with the definition. However, the special access needed is visible only when the definition is available. So the above should be an error, and information from the definition cannot affect the access of the default arguments.

Proposed Resolution (April 2003):

Add a new paragraph 16 to 13.2 [temp.param] after paragraph 15:

Since a default template-argument is encountered before any base-clause there is no special access to members used in a default template-argument. [Example:
  class B {};
  template <class T> class C {
  protected:
     typedef T TT;
  };

  template <class U, class V = typename U::TT>
  class D : public U {};

  D <C<B> > d;  // access error, C::TT is protected
--- end example]

Notes from October 2003 meeting:

We decided that template parameter default arguments should have their access checked in the context where they appear without special access for the entity declared (i.e., they are different than normal function default arguments). One reason: we don't know the instance of the template when we need the value. Second reason: compilers want to parse and throw away the form of the template parameter default argument, not save it and check it for each instantiation.

Class templates should be treated the same as function templates in this regard. The base class information is in the same category as friend declarations inside the class itself -- not available. If the body were used one would need to instantiate it in order to know whether one can name it.

Proposed resolution (October, 2004):

Add the following as a new paragraph following the last paragraph of 11.8 [class.access] (but before the new paragraph inserted by the resolution of issue 372, if adopted):

The names in a default template-argument (13.2 [temp.param]) have their access checked in the context in which they appear rather than at any points of use of the default template-argument. [Example:

    class B {};
    template <class T> class C {
    protected:
       typedef T TT;
    };

    template <class U, class V = typename U::TT>
    class D : public U {};

    D <C<B> >* d;  // access error, C::TT is protected

end example]