Issue 250516.1: Support C++0x Variadic templates

Author: Kendrick Wong
Champion: Jason Merrill
Date submitted: 2025-05-16
Date revised: 2025-09-15
Date closed: 2025-08-04
Type: Enhancement
Status: Accepted
DWARF version: 6

This proposal was originally submitted as 090107.2.

In the DWARF commmittee meeting on June 2, 2009, four options were presented:

  1. DW_TAG_template_parameter_pack/DW_TAG_formal_parameter_pack is used as marker.
  2. Make DW_TAG_template_type_parameter DIEs children of DW_TAG_template_parameter_pack. And make DW_TAG_formal_parameter DIEs children of DW_TAG_formal_parameter_pack.
  3. Create new children DIEs under DW_TAG_template_parameter_pack/DW_TAG_formal_parameter_pack DIE and add references to DW_TAG_template_type_parameter/DW_TAG_formal_parameter respectively.
  4. Reject Variadic templates proposal.

The consensus was to reject the proposal and wait for a vendor to produce the information first.

Background

For a detailed description of the feature, please refer to:

Overview

C++0x will allow function and class templates to take an arbitrary number of arguments. The motivation behind this language extension is to allow TR1 facilities such as tuple to accept variable number of parameters.

template<typename... Elements> class tuple;
tuple<int, long> tuple_int_long;  // Elements is a template type parameter pack
                                  // containing 2 arguments, int and long type
tuple<float> tuple_float;         // Elements is a template type parameter pack
                                     containing 1 argument: float type

template<typename T, unsigned PrimaryDimension, unsigned... Dimensions> class array;
array<double, 3, 3> t1;           // Dimensions is a template value parameter pack
                                  // containing a single argument: unsigned int 3.
array<double, 3, 3, 4, 5> t2;     // Dimensions is a template value parameter pack
                                  // containing three arguments: unsigned int 3, 4 and 5.

template<typename... Args> void eat(Args... args);
// The eat() function is a variadic template with template parameter pack Args.
// The ellipsis to the left of the identifier args indicates that args is a
//   function parameter pack.

Proposed changes to DWARF

Purpose

New DWARF tags

Add the following new tags to Table 2.1, "Tag names", to Table 7.3, "Tag encodings", and to Table A.1, "Attributes by tag value":

2.23: Template Parameters

Replace the third and fourth paragraphs with the following:

A template type parameter is represented by a debugging information entry with the tag DW_TAG_template_type_parameter. A template value parameter is represented by a debugging information entry with the tag DW_TAG_template_value_parameter. A template parameter pack is represented by a debugging information entry with the tag DW_TAG_template_parameter_pack. The actual template parameter entries appear in the same order as the corresponding template formal parameter declarations in the source program.

Each element of a parameter pack is represented by a debugging information entry for a type or value parameter. These entries are children of the debugging information entry with the tag DW_TAG_template_parameter_pack. Each such entry does not have a DW_AT_name attribute.

Except as above, a type or value parameter or parameter pack entry may have a DW_AT_name attribute, whose value is a null-terminated string containing the name of the corresponding formal parameter. The A type or value parameter entry may also have a DW_AT_default_value attribute, which is a flag indicating that the value corresponds to the default argument for the template parameter.

3.3.7: Function Template Instantiations

Add the following numbered item following item #1 (renumbering items 2 and 3):

2. Each function parameter pack declaration appearing in the template definition is represented by a debugging information entry with the tag DW_TAG_formal_parameter_pack. Each such entry may have a DW_AT_name attribute, whose value is a null-terminated string containing the name of the function parameter pack as it appears in the source program.

Each element of the function parameter pack is represented by a debugging information entry with the tag DW_TAG_formal_parameter. These entries are children of the debugging information entry with the tag DW_TAG_formal_parameter_pack. Each such entry does not have a DW_AT_name attribute. Each such entry has a DW_AT_type attribute describing the type of the formal parameter in this instantiation.

APPENDIX D: Examples

D.8 Variadic Templates Examples

D.8.1 Function Template Instantiations

/* Base case for printf */
void printf(const char* s) {
  while (*s) {
    std::cout << *s++;
  }
}
template<typename T, typename... PackTypes>
void printf(const char* s, T value, PackTypes... args) {
  while (*s) {
    if (*s == '%' && *++s != '%') {
      std::cout << value;
      return printf (++s, args...);
    }
    std::cout << *s++;
  }
}

int x;
printf<int, char, int> ("%c %d", x, 'x', 3);

The base case for printf is not a template instantiation:

printf (const char* s);
1$:   DW_TAG_subprogram
          DW_AT_name("printf")
2$:       DW_TAG_formal_parameter
              DW_AT_name("s")
              DW_AT_type(reference to type "const char*")

Compiler may instantiate these 3 functions:

# printf<int,char,int> (const char* s, int value, char, int);  // args => char, int
# printf<char,int>     (const char* s, char value, int);       // args => int
# printf<int>          (const char* s, int value);             // args => (empty)

1) printf<int,char,int> (const char* s, int value, char, int);  // args => char, int
10$:  DW_TAG_subprogram
          DW_AT_name("printf")
11$:      DW_TAG_template_type_parameter
              DW_AT_name("T")
              DW_AT_type(reference to base type "int")
12$:      DW_TAG_template_parameter_pack
              DW_AT_name("PackTypes")
13$:          DW_TAG_template_type_parameter
                  ! no DW_AT_name attribute
                  DW_AT_type(reference to base type "char")
14$:          DW_TAG_template_type_parameter
                  ! no DW_AT_name attribute
                  DW_AT_type(reference to base type "int")
15$:      DW_TAG_formal_parameter
              DW_AT_name("s")
              DW_AT_type(reference to type "const char*")
16$:      DW_TAG_formal_parameter
              DW_AT_name("value")
              DW_AT_type(reference to base type "int")
17$:      DW_TAG_formal_parameter_pack
              DW_AT_name("args")
18$:          DW_TAG_formal_parameter
                  ! no DW_AT_name attribute
                  DW_AT_type(reference to base type "char")
19$:          DW_TAG_formal_parameter
                  ! no DW_AT_name attribute
                  DW_AT_type(reference to base type "int")

2) printf<char,int>     (const char* s, char value, int);       // args => int
20$:  DW_TAG_subprogram
          DW_AT_name("printf")
21$:      DW_TAG_template_type_parameter
              DW_AT_name("T")
              DW_AT_type(reference to base type "int")
22$:      DW_TAG_template_parameter_pack
              DW_AT_name("PackTypes")
23$:          DW_TAG_template_type_parameter
                  ! no DW_AT_name attribute
                  DW_AT_type(reference to base type "int")
24$:      DW_TAG_formal_parameter
              DW_AT_name("s")
              DW_AT_type(reference to type "const char*")
25$:      DW_TAG_formal_parameter
              DW_AT_name("value")
              DW_AT_type(reference to base type "char")
26$:      DW_TAG_formal_parameter_pack
              DW_AT_name("args")
27$:          DW_TAG_formal_parameter
                  ! no DW_AT_name attribute
                  DW_AT_type(reference to base type "int")

3) printf<int>          (const char* s, int value);             // args => (empty)
30$:  DW_TAG_subprogram
          DW_AT_name("printf")
31$:      DW_TAG_template_type_parameter
              DW_AT_name("T")
              DW_AT_type(reference to base type "int")
32$:      DW_TAG_template_parameter_pack
              DW_AT_name("PackTypes")
33$:      DW_TAG_formal_parameter
              DW_AT_name("s")
              DW_AT_type(reference to type "const char*")
34$:      DW_TAG_formal_parameter
              DW_AT_name("value")
              DW_AT_type(reference to base type "int")
35$:      DW_TAG_formal_parameter_pack
              DW_AT_name("args")

D.8.2 Class Template Instantiations

/* Template definition for counting number of template type arguments */
template<typename... PackTypes> struct count;

/* Full specialization for zero argument */
template <>
struct count<> {
  static const int value = 0;
};

/* Partial specialization for peeling off the first argument */
template<typename T, typename... PackTypes>
struct count<T, PackTypes...> {
  static const int value = 1 + count<PackTypes...>::value;
};

/* Template instantiation */
count<char, short, int> a;

The base case template:

1$:   DW_TAG_structure_type
          DW_AT_name("count")
2$:       DW_TAG_member
              DW_AT_name("value")
              DW_AT_declaration(yes)
              DW_AT_type(reference to type "const int")
3$:   DW_TAG_variable
          DW_AT_specification(reference to 2$)
          DW_AT_location(...)

Compiler may instantiate these 3 types:

1) count<char, short, int>      // PackTypes => short, int
11$:  DW_TAG_structure_type
          DW_AT_name("count")
12$:      DW_TAG_template_type_parameter
              DW_AT_name("T")
              DW_AT_type(reference to base type "char")
13$:      DW_TAG_template_parameter_pack
              DW_AT_name("PackTypes")
14$:          DW_TAG_template_type_parameter
                  DW_AT_type(reference to base type "short")
15$:          DW_TAG_template_type_parameter
                  DW_AT_type(reference to base type "int")
16$:      DW_TAG_member
              DW_AT_name("value")
              DW_AT_declaration(yes)
              DW_AT_type(reference to type "const int")
17$:  DW_TAG_variable
          DW_AT_specification(reference to 16$)
          DW_AT_location(...)

2) count<short, int>            // PackTypes => int
21$:  DW_TAG_structure_type
          DW_AT_name("count")
22$:      DW_TAG_template_type_parameter
              DW_AT_name("T")
              DW_AT_type(reference to base type "short")
23$:      DW_TAG_template_parameter_pack
              DW_AT_name("PackTypes")
24$:          DW_TAG_template_type_parameter
                  DW_AT_type(reference to base type "int")
25$:      DW_TAG_member
              DW_AT_name("value")
              DW_AT_declaration(yes)
              DW_AT_type(reference to type "const int")
26$:  DW_TAG_variable
          DW_AT_specification(reference to 25$)
          DW_AT_location(...)

3) count<int>                   // PackTypes => (empty)
31$:  DW_TAG_structure_type
          DW_AT_name("count")
32$:      DW_TAG_template_type_parameter
              DW_AT_name("T")
              DW_AT_type(reference to base type "int")
33$:      DW_TAG_template_parameter_pack
              DW_AT_name("PackTypes")
34$:      DW_TAG_member
              DW_AT_name("value")
              DW_AT_declaration(yes)
              DW_AT_type(reference to type "const int")
35$:  DW_TAG_variable
          DW_AT_specification(reference to 34$)
          DW_AT_location(...)

4) count<char, short, int> a;
41$:  DW_TAG_variable
          DW_AT_name("a")
          DW_AT_type(reference to 11$)
          DW_AT_location(...)

D.8.3 Multiple template packs in template definition

template <class X,int I>
struct pair {
  void showself () {
    std::cout << I << std::endl;
    X local;
    local.showself();
  }
};

struct a1 { void showself () { std::cout << "a1" << std::endl; }};
struct a2 { void showself () { std::cout << "a2" << std::endl; }};

template <class headX, int headI, class... restX, int... restI>
void showself (pair<headX, headI> headArg, pair<restX, restI>... restArg) {
  headArg.showself();
  showself (restArg...);
}

/* Instantiations */
pair<a1,1> t1;
pair<a2,2> t2;
showself(t1,t2);

First the simple structures:

struct a1 { void showself () { std::cout << "a1" << std::endl; }};

11$:   DW_TAG_structure_type
          DW_AT_name("a1")
12$:      DW_TAG_subprogram
              DW_AT_name("showself")
              DW_AT_type(reference to type "void")

struct a2 { void showself () { std::cout << "a2" << std::endl; }};

21$:   DW_TAG_structure_type
          DW_AT_name("a2")
22$:      DW_TAG_subprogram
              DW_AT_name("showself")
              DW_AT_type(reference to type "void")

DWARF for 'pair' structures:

pair<a1,1> t1;

31$:   DW_TAG_structure_type
          DW_AT_name("pair")
32$:      DW_TAG_template_type_parameter
              DW_AT_name("X")
              DW_AT_type(reference to 11$)
33$:      DW_TAG_template_value_parameter
              DW_AT_name("I")
              DW_AT_type(reference to base type "int")
              DW_AT_const_value(1)
33$:      DW_TAG_subprogram
              DW_AT_name("showself")
              DW_AT_type(reference to type "void")
34$:  DW_TAG_variable
          DW_AT_name("t1")
          DW_AT_type(reference to 31$)
          DW_AT_location(...)

pair<a2,2> t2;

41$:   DW_TAG_structure_type
          DW_AT_name("pair")
42$:      DW_TAG_template_type_parameter
              DW_AT_name("X")
              DW_AT_type(reference to 21$)
43$:      DW_TAG_template_value_parameter
              DW_AT_name("I")
              DW_AT_type(reference to base type "int")
              DW_AT_const_value(2)
43$:      DW_TAG_subprogram
              DW_AT_name("showself")
              DW_AT_type(reference to type "void")
44$:  DW_TAG_variable
          DW_AT_name("t2")
          DW_AT_type(reference to 41$)
          DW_AT_location(...)

The variadic template function showself():

template <class headX, int headI, class... restX, int... restI>
void showself (pair<headX, headI> headArg, pair<restX, restI>... restArg) {
  headArg.showself();
  showself (restArg...);
}

showself (pair<struct a1,1>, pair<struct a2,2>):

51$:  DW_TAG_subprogram
          DW_AT_name("showself")
52$:      DW_TAG_template_type_parameter
              DW_AT_name("headX")
              DW_AT_type(reference to 11$)
53$:      DW_TAG_template_value_parameter
              DW_AT_name("headI")
              DW_AT_type(reference to base type "int")
              DW_AT_const_value(1)
54$:      DW_TAG_template_parameter_pack
              DW_AT_name("restX")
55$:          DW_TAG_template_type_parameter
                  DW_AT_type(reference to 21$)
56$:      DW_TAG_template_parameter_pack
              DW_AT_name("restI")
              DW_AT_type(reference to base type "int")
57$:          DW_TAG_template_value_parameter
                  DW_AT_const_value(2)
58$:      DW_TAG_formal_parameter
              DW_AT_name("headArg")
              DW_AT_type(reference to 31$)
59$:      DW_TAG_formal_parameter_pack
              DW_AT_name("restArg")
60$:          DW_TAG_formal_parameter
                  ! no DW_AT_name attribute
                  DW_AT_type(reference to 41$)

showself (pair<struct a2,2>):

71$:  DW_TAG_subprogram
          DW_AT_name("showself")
72$:      DW_TAG_template_type_parameter
              DW_AT_name("headX")
              DW_AT_type(reference to 21$)
73$:      DW_TAG_template_value_parameter
              DW_AT_name("headI")
              DW_AT_type(reference to base type "int")
              DW_AT_const_value(2)
74$:      DW_TAG_template_parameter_pack
              DW_AT_name("restX")
75$:      DW_TAG_template_parameter_pack
              DW_AT_name("restI")
76$:      DW_TAG_formal_parameter
              DW_AT_name("headArg")
              DW_AT_type(reference to 41$)
77$:      DW_TAG_formal_parameter_pack
              DW_AT_name("restArg")

Change History

March 17, 2009.

April 13, 2009.

May 5, 2009.

June 2, 2009.

September 11, 2009.

July 6, 2025.


2025-08-04: Accepted, with possible editorial changes.

2025-09-15: Editorial changes. List tables needing change due to new DWARF tags; Clarify scope of changes to Sections 2.23 and 3.3.7; Clarified text to disallow DW_AT_default_value attribute on parameter pack entries. In Section 3.3.7, combined items 4 and 5 and inserted between old items 1 and 2. Of the examples given, only the printf example will be added to Appendix D.