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

2024-03-20


778. Template parameter packs in non-type template parameters

Section: 13.2  [temp.param]     Status: C++11     Submitter: Michael Wong     Date: 13 February, 2009

[Voted into the WP at the March, 2011 meeting as part of paper N3270.]

Consider an example like:

    template <typename T, T Value> struct bar { };
    template <typename... T, T ...Value> void foo(bar<T, Value>);

The current wording in 13.2 [temp.param] is unclear as to whether this is permitted or not. For comparison, 9.3.4.6 [dcl.fct] paragraph 13 says,

A declarator-id or abstract-declarator containing an ellipsis shall only be used in a parameter-declaration. Such a parameter-declaration is a parameter pack (13.7.4 [temp.variadic]). When it is part of a parameter-declaration-clause, the parameter pack is a function parameter pack (13.7.4 [temp.variadic]). [Note: Otherwise, the parameter-declaration is part of a template-parameter-list and the parameter pack is a template parameter pack; see 13.2 [temp.param]. —end note] A function parameter pack, if present, shall occur at the end of the parameter-declaration-list. The type T of the declarator-id of the function parameter pack shall contain a template parameter pack; each template parameter pack in T is expanded by the function parameter pack.

The requirement here that the type of a function parameter pack must contain a template parameter pack is not repeated for template non-type parameters in 13.2 [temp.param], nor is the statement that it expands the template parameter pack.

A related issue is that neither function nor template parameter packs are listed in 13.7.4 [temp.variadic] paragraph 4 among the contexts in which a pack expansion can appear.

Proposed resolution (November, 2010):

  1. Change 7.6.2.5 [expr.sizeof] paragraph 5 as follows:

  2. The identifier in a sizeof... expression shall name a parameter pack. The sizeof... operator yields the number of arguments provided for the parameter pack identifier. The parameter pack is expanded (13.7.4 [temp.variadic]) by the sizeof... operator A sizeof... expression is a pack expansion (13.7.4 [temp.variadic]). [Example:...
  3. Change 9.3.4.6 [dcl.fct] paragraph 13 as follows:

  4. A declarator-id or abstract-declarator containing an ellipsis shall only be used in a parameter-declaration. Such a parameter-declaration is a parameter pack (13.7.4 [temp.variadic]). When it is part of a parameter-declaration-clause, the parameter pack is a function parameter pack (13.7.4 [temp.variadic]). [Note: Otherwise, the parameter-declaration is part of a template-parameter-list and the parameter pack is a template parameter pack; see 13.2 [temp.param]. —end note] The type T of the declarator-id of the function parameter pack shall contain a template parameter pack; each template parameter pack in T is expanded by the function parameter pack A function parameter pack is a pack expansion (13.7.4 [temp.variadic]). [Example:...
  5. Change 13.2 [temp.param] paragraph 15 as follows:

  6. If a template-parameter is a type-parameter with an ellipsis prior to its optional identifier or is a parameter-declaration that declares a parameter pack (9.3.4.6 [dcl.fct]), then the template-parameter is a template parameter pack (13.7.4 [temp.variadic]). A template parameter pack that is a parameter-declaration whose type contains one or more unexpanded parameter packs is a pack expansion. Similarly, a template parameter pack that is a type-parameter with a template-parameter-list containing one or more unexpanded parameter packs is a pack expansion. [Example:

      template <class... Types> class Tuple; // Types is a template type parameter pack and a pack expansion
      template <class T, int... Dims> struct multi_array; // Dims is a non-type template parameter pack but not a pack expansion
      template <class T, T... Values> struct static_array; // Values is a non-type template parameter pack and a pack expansion
    
  7. Change 13.7.4 [temp.variadic] paragraphs 4-6 and add a new paragraph 7 as follows:

  8. A pack expansion is a sequence of tokens that names one or more parameter packs, followed by an ellipsis. The sequence of tokens is called the pattern of the expansion; its syntax consists of a pattern and an ellipsis, the instantiation of which produces zero or more instantiations of the pattern in a list (described below). The form of the pattern depends on the context in which the expansion occurs. Pack expansions can occur in the following contexts:

    [Example:...

    A parameter pack whose name appears within the pattern of a pack expansion is expanded by that pack expansion. An appearance of the name of a parameter pack is only expanded by the innermost enclosing pack expansion. The pattern of a pack expansion shall name one or more parameter packs that are not expanded by a nested pack expansion; such parameter packs are called unexpanded parameter packs in the pattern. All of the parameter packs expanded...

      ...
      void g(Args ... args) {  // OK: “Args” is expanded by the function parameter pack “args
      ...
    

    The instantiation of an a pack expansion that is not a sizeof... expression produces a list...

    The instantiation of a sizeof... expression (7.6.2.5 [expr.sizeof]) produces an integral constant containing the number of elements in the parameter pack it expands.

This resolution also resolves issues 1182 and 1183.

Additional note (February, 2011):

A problematic case is a function like

  template<typename... T, T... t> void f(T...) { }

where each element of the nontype pack actually has a different type. This causes problems for template argument deduction, since T and t are supposed to be deduced independently, but they're linked through their sizes. There doesn't appear to be any use case for this kind of example, so it should be ill-formed.

The rule should probably be to consider a non-type template parameter pack that expands any template parameter packs from the same template-parameter-list as ill-formed.