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

2023-01-15


184. Default arguments in template template-parameters

Section: 13.2  [temp.param]     Status: CD1     Submitter: John Spicer     Date: 11 Nov 1999

[Voted into WP at April 2003 meeting.]

John Spicer: Where can default values for the template parameters of template template parameters be specified and where so they apply?

For normal template parameters, defaults can be specified only in class template declarations and definitions, and they accumulate across multiple declarations in the same way that function default arguments do.

I think that defaults for parameters of template template parameters should be handled differently, though. I see no reason why such a default should extend beyond the template declaration with which it is associated. In other words, such defaults are a property of a specific template declaration and are not part of the interface of the template.

    template <class T = float> struct B {};

    template <template <class _T = float> class T> struct A {
        inline void f();
        inline void g();
    };

    template <template <class _T> class T> void A<T>::f() {
        T<> t;  // Okay? (proposed answer - no)
    }

    template <template <class _T = char> class T> // Okay? (proposed answer - yes)
    void A<T>::g() {
        T<> t;  // T<char> or T<float>?  (proposed answer - T<char>)
    }

    int main() {
        A<B> ab;
        ab.f();
    }

I don't think this is clear in the standard.

Gabriel Dos Reis: On the other hand I fail to see the reasons why we should introduce yet another special rule to handle that situation differently. I think we should try to keep rules as uniform as possible. For default values, it has been the case that one should look for any declaration specifying default values. Breaking that rules doesn't buy us anything, at least as far as I can see. My feeling is that [allowing different defaults in different declarations] is very confusing.

Mike Miller: I'm with John on this one. Although we don't have the concept of "prototype scope" for template parameter lists, the analogy with function parameters would suggest that the two declarations of T (in the template class definition and the template member function definition) are separate declarations and completely unrelated. While it's true that you accumulate default arguments on top-level declarations in the same scope, it seems to me a far leap to say that we ought also to accumulate default arguments in nested declarations. I would expect those to be treated as being in different scopes and thus not to share default argument information.

When you look up the name T in the definition of A<T>::f(), the declaration you find has no default argument for the parameter of T, so T<> should not be allowed.

Proposed Resolution (revised October 2002):

In 13.2 [temp.param], add the following as a new paragraph at the end of this section:

A template-parameter of a template template-parameter is permitted to have a default template-argument. When such default arguments are specified, they apply to the template template-parameter in the scope of the template template-parameter. [Example:
    template <class T = float> struct B {};

    template <template <class TT = float> class T> struct A {
        inline void f();
        inline void g();
    };

    template <template <class TT> class T> void A<T>::f() {
        T<> t;  // error - TT has no default template argument
    }

    template <template <class TT = char> class T>void A<T>::g() {
        T<> t;  // OK - T<char>
    }
-- end example]