clang/gcc difference regarding inference of array reference from braced list

57 views
Skip to first unread message

jere...@gmail.com

unread,
May 28, 2018, 10:41:17 PM5/28/18
to ISO C++ Standard - Discussion
Clang accepts the following:
template <int N>
void foo(const long (&arr)[N]) {}
void bar() {
 foo
({1,2,3});
}

GCC gives an error:

<source>: In function 'void bar()':

<source>:4:16: error: no matching function for call to 'foo(<brace-enclosed initializer list>)'

foo({1,2,3});

^

<source>:2:6: note: candidate: 'template<int N> void foo(const long int (&)[N])'

void foo(const long (&arr)[N]) {}

^~~

<source>:2:6: note: template argument deduction/substitution failed:

<source>:4:16: note: mismatched types 'long int' and 'int'

foo({1,2,3});

^

Compiler returned: 1


Compiler explorer link:

https://godbolt.org/g/rjqaq3

Which compiler is correct? The Clang behavior seems to be more desirable.

Edward Catmur

unread,
May 29, 2018, 8:53:59 AM5/29/18
to ISO C++ Standard - Discussion, jere...@gmail.com
Per [temp.deduct.call]/1, given parameter type long[N] and argument {1, 2, 3} we deduce N to be 3 and replace that parameter with multiple parameters "long, long, long" with corresponding argument types "int, int, int"; there is no further deduction to perform. Figuratively:

template<int N> void foo_(long, long, long);
void bar() { foo_<3>(1, 2, 3); }

As described in [temp.deduct.call]/10, implicit conversion succeeds for each argument. We then check the deduced function template for viability [over.match.viable] which requires an implicit conversion sequence [over.best.ics] for each argument; since the argument is an initializer list and the parameter is an array, [over.ics.list]/6 applies and we seek an implicit conversion from each list element (of type int) to the corresponding array element type (long) giving an overall conversion rank of integral conversion. Thus clang is correct to accept the call.

However, note that clang rejects and gcc accepts the similar code:

template<class T, int N> void h(T x, decltype(x) const(&arr)[N]);
int main() { h(1l, {1, 2, 3}); }

In this case, T is deduced to long; in the second parameter N is deduced to 3 and the parameter is replaced with 3 parameters decltype(x), a non-deduced type:

template<int N, class T> void h_(T x, decltype(x), decltype(x), decltype(x));
int main() { h_<3>(1l, 1, 2, 3); }

Reasoning proceeds similarly, so this code should likewise be accepted.

icc behaves the same as gcc; MSVC accepts both.

It would be nice were this case covered by an example under [temp.deduct.call]/1.

jere...@gmail.com

unread,
May 29, 2018, 12:31:17 PM5/29/18
to ISO C++ Standard - Discussion, jere...@gmail.com
Thanks for the clarification.  I filed a GCC bug:

Reply all
Reply to author
Forward
0 new messages