title: Using C++ variadic templates to initialize variable-length arrays in static structs
body: <p>I've been writing some code that deals with USB at the packet level. One "hangup" I've run into is that with USB, you have some structs that contain arrays of other structs (not pointers):</p>
  
  <pre><code>typedef struct {
      uint8_t bLength;
      uint8_t bDescriptorType;
      uint8_t bEndpointAddress;
      uint8_t bmAttributes;
      uint16_t wMaxPacketSize;
      uint8_t bInterval;
  } PACKED endp_descriptor_t;
  
  typedef struct {
      uint8_t bLength;
      uint8_t bDescriptorType;
      uint8_t bInterfaceNumber;
      uint8_t bAlternateSetting;
      uint8_t bNumEndpoints;
      uint8_t bInterfaceClass;
      uint8_t bInterfaceSubClass;
      uint8_t bInterfaceProtocol;
      uint8_t iInterface;
      endp_descriptor_t endpoints[];
  } PACKED int_descriptor_t;
  
  typedef struct {
      uint8_t  bLength;
      uint8_t  bDescriptorType;
      uint16_t wTotalLength;
      uint8_t  bNumInterfaces;
      uint8_t  bConfigurationValue;
      uint8_t  iConfiguration;
      uint8_t  bmAttributes;
      uint8_t  bMaxPower;
      int_descriptor_t interfaces[];
  } PACKED cfg_descriptor_t;
  </code></pre>
  
  <p>The <code>cfg_descriptor_t</code> contains zero or more <code>int_descriptor_t</code>s, and each <code>int_descriptor_t</code> contains zero or more <code>endp_descriptor_t</code>s.</p>
  
  <p>I'm working on a microcontroller with fairly limited space (256K flash, 64K RAM), so I wanted to avoid dynamic allocation as much as possible and define these structs at compile time:</p>
  
  <pre><code>static cfg_descriptor_t cfg_descriptor = {
      .bLength =             9,
      .bDescriptorType =     2, //config descriptor
      .wTotalLength =        18,
      .bNumInterfaces =      1,
      .bConfigurationValue = 1,
      .iConfiguration =      0,
      .bmAttributes =        0x80, //bus powered, no remote wakeup
      .bMaxPower =           250, //x2 = 500mA (maximum allowed by spec)
      .interfaces =          {
          {
              .bLength =            9,
              .bDescriptorType =    4, //interface
              .bInterfaceNumber =   0,
              .bAlternateSetting =  0,
              .bNumEndpoints =      1,
              .bInterfaceClass =    0xFF,
              .bInterfaceSubClass = 0x0,
              .bInterfaceProtocol = 0x0,
              .iInterface =         0,
              .endpoints = {
                  {
                      .bLength =  7,
                      .bDescriptorType = 5, //endpoint
                      .bEndpointAddress = 0x81,
                      .bmAttributes = 0x03,
                      .wMaxPacketSize = 64,
                      .bInterval = 10,
                  }
              }
          }
      }
  };
  </code></pre>
  
  <p>Unfortunately, it seems gcc doesn't understand what I'm trying to do here, and complains about <code>too many initializers for ‘int_descriptor_t [0]’</code> - i.e. it apparently can't determine the length of the array from the initializers. (Maybe I've just made some simple mistake here?)</p>
  
  <p>I thought I might take advantage of C++11's variadic templates for this:</p>
  
  <pre><code>template&lt;typename... interfaces&gt;
  struct PACKED x_cfg_descriptor_t {
      uint8_t  bLength;
      uint8_t  bDescriptorType;
      uint16_t wTotalLength;
      uint8_t  bNumInterfaces;
      uint8_t  bConfigurationValue;
      uint8_t  iConfiguration;
      uint8_t  bmAttributes;
      uint8_t  bMaxPower;
      interfaces...;
  };
  </code></pre>
  
  <p>but this doesn't work either: <code>expected unqualified-id before ‘...’ token</code> on the <code>interfaces...</code> line.</p>
  
  <p>I've seen some examples of variable-sized tuples using variadic templates, but I couldn't quite understand what they were doing, and they suggested that the actual layout in memory would be in reverse order of the template parameters. (I think recursive templates are involved...)</p>
  
  <p>So the question is: can I define a static struct instance with a variable number of members at compile time?</p>