Why are the next two template declarations ambiguous (so neither is more specialized than the other)? I know this question has been raised many times on Stack Overflow, but usually, people answer how to resolve ambiguity, not why it's happened.
I.
template <class T> void func(char* buf, T size) {}
II.
template <std::size_t N> void func(char (&buf)[N], std::size_t size) {}
Trying to pass steps of the C++14 standard to resolve partial function template ordering (14.5.6.2):
To produce the transformed template, for each type, non-type, or template template parameter (including template parameter packs (14.5.3) thereof) synthesize a unique type, value, or class template respectively and substitute it for each occurrence of that parameter in the function type of the template.
Transformed function I template's function type is: void func(char*, U1)
, where U1
is some unique synthetic type.
Transformed function II template's function type is: void func(char (&buf)[N1], std::size_t)
, where N1
is some unique synthetic value.
Using the transformed function template’s function type, perform type deduction against the other template as described in 14.8.2.4.
So let's try to perform type deduction on one side (using the first template as an argument and the second one as a parameter template) and on the opposite side.
Case 1.
Parameter template: template <std::size_t N> void func(char (&buf)[N], std::size_t size)
.
Transformed argument template: void func(char*, U1)
.
Trying to deduce template parameters. "char (&buf)[N]
" can't be deduced from "char*
" type. U1 doesn't match std::size_t
type either. Failed.
Case 2.
Parameter template: template <class T> void func(char* buf, T size)
.
Transformed argument template: void func(char (&buf)[N1], std::size_t)
.
Trying to deduce template parameters. The first argument of parameter template is not type at all and it's compatible with a char[]
. T
should be deduced to std::size_t
.
So template II should be more specialized and should be selected in the following code:
char buf[16];
func(buf, static_cast<std::size_t>(16));
Why is this not true for GCC 5.3 and for Clang 4.0?
The template declarations are not ambiguous; the following code compiles and runs OK:
However, the commented-out call is ambiguous. To disambiguate it use:
This works OK and calls the correct function.