Created attachment 25581 [details] sample1 doesn't compile, whereas sample2 and sample3 do compile. The title says it all. sample1.cc does not compile, however, sample2.cc and sample3.cc do. Both were compiled with the -Wall and -std=gnu++0x flags. The expected output of sample2.cc should be: array[4] plus variadic pointer plus variadic variadic array[4] pointer generic However, ends up being: pointer plus variadic pointer plus variadic variadic pointer pointer generic Similarly, sample3.cc ends up being: variadic variadic generic generic Instead of: array[4] plus variadic variadic array[4] generic The GCC does not see any difference between void f(int[N]) and void f(int*). If you try to define two functions, it will say that void f(int*) is already defined, even if you are defining void f(int[N]) instead. You can get around this with some messy template work (as seem in the second sample), but it doesn't work as expected. Using templates, a specialization of int* will always take precedence over a specialization of int[N]. If I define a variadic function with an int[4] head and one without a head at all, it will assume the non-specialized version, which is incorrect (see sample3.cc). If you define a function with an int* head, it will work, but in that case, you cannot define the function as constexpr.
According to [dcl.fct] p5, "any parameter of type “array of T” or “function returning T” is adjusted to be “pointer to T” or “pointer to function returning T,” respectively. [..] The resulting list of transformed parameter types and the presence or absence of the ellipsis or a function parameter pack is the function’s parameter-type-list." This has the effect that void f4(int* x); and void f4(int x[4]); are essentially equivalent declarations of the same function. The same rationale applies to template<class... T> void f2(int* x, T... y); versus template<class... T> void f2(int x[4], T... y); so in sample1 you are violating the ODR two times in a form that requires a diagnostic. This rationale cannot be applied directly to templates, because due to SFINAE you could render one instantiation invalid (e.g. when attempting to instantiate an array of zero or negative size) and it is allowed for two different function template specializations to have the same type ([temp.over.link] p1). But according to [temp.deduct.call] p2: "If P is not a reference type: — If A is an array type, the pointer type produced by the array-to-pointer standard conversion (4.2) is used in place of A for type deduction;" This has basically the effect that an example like template<class T, int N> void g(T x[N]) {} int main() { int a[4]; g(a); } can never be well-formed, because N cannot be (implicitly) deduced from an effective argument of type int*. This explains the effect that the template examples alway select the pointer overload, not the array overload. So, from what I see so far this issue is invalid.
(In reply to comment #0) > The GCC does not see any difference between void f(int[N]) and void f(int*) Because they're the same. See Daniel's answer for more detail.