4

I recently learnt about parameter packs. Then I wrote the following program that compiles with msvc but not with clang and gcc. Live demo:

#include <array>

template<typename T, std::size_t... rows> int func(T (&arr...)[rows])    
{
   return 5;  
}
int main()
{
    
    int arr[2][3][4];
    auto a = func(arr);
    
}

As can be seen in the above demo, msvc compiles it but gcc says:

<source>:3:56: error: 'arr' was not declared in this scope
    3 | template<typename T, std::size_t... rows> int func(T (&arr...)[rows])
      |                                                        ^~~
<source>:3:69: error: parameter packs not expanded with '...':
    3 | template<typename T, std::size_t... rows> int func(T (&arr...)[rows])
      |                                                                     ^
<source>:3:69: note:         'rows'
<source>:6:2: error: expected ';' before 'int'
    6 | }
      |  ^
      |  ;
    7 | int main()
      | ~~~
Compiler returned: 1

I want to know which compiler is correct and the reason.

Jason
  • 36,170
  • 5
  • 26
  • 60
Alan
  • 116
  • 9

2 Answers2

4

The syntax for a parameter pack has ... in front of the declarator-id:

template<typename T, std::size_t... rows> int func(T (&...arr)[rows])    
{
   return 5;  
}

This is the same for simpler parameter packs:

template<typename... Ts>
void test(Ts ...arr);

Whitespace doesn't matter and Ts... arr is a more common style but doesn't reflect well that ... is part of the declarator ...arr, not of the type specifier Ts.

MSVC seems to accept the syntax with ... after the declarator-id arr for some reason, but that should be ill-formed. However, MSVC does give it the same meaning as the correct order would, see below.


But it doesn't have the meaning you intent it to have. T (&...arr)[rows] expands to a list of parameters of the form T (&arr1)[rows1], T (&arr2)[rows2], T (&arr3)[rows3] and so on. You can't add [rowsN] syntax to a parameter's type with a pack expansion.

In your call auto a = func(arr);, T will be int[3][4] and rows will have a single element with value 2.

user17732522
  • 53,019
  • 2
  • 56
  • 105
2

The program is ill-formed because when introducing a function parameter pack the ellipsis ... that expands a template parameter pack must appear prior to or in place of the function parameter name.

In other words, the ... should be placed before the function parameter name b so that the corrected program would look like:

//-----------------------------------------------------vvv------------>prior to function parameter name 
template<typename T, std::size_t... rows> int func(T (&...arr)[rows])    
{
   return 5;  
}
int main()
{
    
    int arr[2][3][4];
    auto a = func(arr);
    
}
Alex
  • 318
  • 1
  • 14