¿Por qué una plantilla de C ++ acepta una matriz no más especializada que una que acepta un puntero de acuerdo con GCC 5.3 y Clang 4.0?

¿Por qué las siguientes dos declaraciones de plantilla son ambiguas (por lo que ninguna es más especializada que la otra)? Sé que esta pregunta se ha planteado muchas veces en Stack Overflow, pero por lo general, las personas responden cómo resolver la ambigüedad, no por qué sucedió.

YO.template <class T> void func(char* buf, T size) {}

IItemplate <std::size_t N> void func(char (&buf)[N], std::size_t size) {}

Intentando pasar los pasos del estándar C ++ 14 para resolver el ordenamiento parcial de la plantilla de función (14.5.6.2):

Para producir la plantilla transformada, para cada tipo, parámetro o plantilla de parámetro de plantilla (incluidos los paquetes de parámetros de plantilla (14.5.3) de los mismos) sintetice una plantilla de tipo, valor o clase única, respectivamente, y sustitúyala por cada aparición de ese parámetro en el tipo de función de la plantilla.

El tipo de función de la plantilla de la función transformada I es:void func(char*, U1), dóndeU1 Es un tipo sintético único.

El tipo de función de la plantilla de la función transformada II es:void func(char (&buf)[N1], std::size_t), dóndeN1 Es un valor sintético único.

Utilizando el tipo de función de la plantilla de función transformada, realice la deducción de tipo con respecto a la otra plantilla como se describe en 14.8.2.4.

Entonces, intentemos realizar una deducción de tipo en un lado (usando la primera plantilla como argumento y la segunda como plantilla de parámetro) y en el lado opuesto.

Caso 1.

Plantilla de parámetros:template <std::size_t N> void func(char (&buf)[N], std::size_t size). Plantilla de argumento transformado:void func(char*, U1).

Intentando deducir los parámetros de la plantilla. "char (&buf)[N]"no se puede deducir de"char*"tipo. U1 no coincidestd::size_t escriba cualquiera. Ha fallado.

Caso 2.

Plantilla de parámetros:template <class T> void func(char* buf, T size). Plantilla de argumento transformado:void func(char (&buf)[N1], std::size_t).

Intentando deducir los parámetros de la plantilla. El primer argumento de la plantilla de parámetros no es tipo y es compatible con unchar[]. T debe deducirse astd::size_t.

Por lo tanto, la plantilla II debería ser más especializada y debería seleccionarse en el siguiente código:

char buf[16];
func(buf, static_cast<std::size_t>(16));

¿Por qué esto no es cierto para GCC 5.3 y Clang 4.0?

Respuestas a la pregunta(1)

Su respuesta a la pregunta