Bug 50839 - Array parameters always take lower precedence than pointer parameters
Summary: Array parameters always take lower precedence than pointer parameters
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.6.1
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-10-23 16:41 UTC by RétroX
Modified: 2011-10-24 00:06 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments
sample1 doesn't compile, whereas sample2 and sample3 do compile. (665 bytes, application/x-gzip)
2011-10-23 16:41 UTC, RétroX
Details

Note You need to log in before you can comment on or make changes to this bug.
Description RétroX 2011-10-23 16:41:46 UTC
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.
Comment 1 Daniel Krügler 2011-10-23 21:30:05 UTC
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.
Comment 2 Jonathan Wakely 2011-10-24 00:03:15 UTC
(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.