Pregunta

Por favor considera este código:

template<typename T>
char (&f(T[1]))[1];

template<typename T>
char (&f(...))[2];

int main() { char c[sizeof(f<void()>(0)) == 2]; }

Esperaba que hiciera SFINAE y eligiera la segunda sobrecarga, ya que la sustitución de T en T [1] produce

 void [1]()

Que es un tipo no válido, por supuesto. El ajuste de los tipos de parámetros (array- > puntero) se realiza después de sustituir los parámetros de la plantilla en los parámetros de la función y verificar los tipos resultantes válidos, como se describe en 14.8.2 [temp.deduct].

Pero tanto Comeau como GCC no compilan lo anterior. Ambos con diferentes diagnósticos.

Comeau dice:

  

" ComeauTest.c " ;, línea 2: error: la matriz de funciones no está permitida char (& amp; f (T [1])) [1];

GCC dice (versión 4.3.3 ):

  

error: ISO C ++ prohíbe la matriz de tamaño cero c

Es decir, GCC no falla en sustituir, pero elige la primera sobrecarga de f , devolviendo un sizeof de 1, en lugar de no sustituirlo por adelantado como Comeau.

¿Qué compilador es correcto y mi código es válido? Consulte o cite la sección estándar adecuada en su respuesta. Gracias!


Actualización : el propio Estándar contiene un ejemplo de este tipo en la lista en 14.8.2 / 2 . No sé por qué lo pasé por alto primero:

template <class T> int f(T[5]);
int I = f<int>(0);
int j = f<void>(0); // invalid array

Si bien el ejemplo es solo informativo, muestra la intención de todos esos párrafos misteriosos y parece mostrar que el código anterior debería funcionar y rechazar la primera sobrecarga.

¿Fue útil?

Solución

Una pequeña nota, aunque muy rara, he encontrado algunas ocasiones en las que Creo que el compilador de Comeau lo tiene mal, aunque estos Las ocasiones son tan raras que siempre vale la pena el doble y el triple. ¡Comprobando tus suposiciones!

Es posible que tenga una razón para el comportamiento de g ++. No estoy seguro de que sea especificado exactamente cuando se ajustan los tipos de parámetros:

Considera lo siguiente:

template<typename T>
struct A
{
  void bar (T[10]);
};

template<typename T>
void A<T>::bar (T*)
{
}

La definición de 'barra' es legal, como " T [10] " se descompone a " T * " hago No veo nada en el estándar que prohíba al compilador realizando los ajustes de 8.3.5 contra la declaración de plantilla, y también mejora el rendimiento cuando se trata de la coincidencia de sobrecarga.

Aplicando esto a su ejemplo, g ++ podría tratarlo como:

template<typename T>
char (&f( T* ))[1];

template<typename T>
char (&f(...))[2];

int main() { char c[sizeof(f<void()>(0)) == 2]; }

En lo anterior, el parámetro sustituido es un puntero legal para función, en lugar de una serie de funciones.

Entonces, la pregunta para mí es - es si hay algo que prohíba ¿Los ajustes para los parámetros de la función (8.3.5) dos veces?

Personalmente, creo que tiene sentido permitir que se realicen los ajustes dos veces ya que de lo contrario complica la coincidencia de la plantilla de función sobrecargas

En conclusión, creo que es válido para g ++ seleccionar la primera sobrecarga basado en cómo trata los parámetros de matriz en descomposición, y Comeau está equivocado no tener un error de deducción para la matriz de funciones.

Por supuesto, esto ahora significa que (si Comeau estaba arreglado) entonces cada compilador Elegiría una sobrecarga diferente y seguiría siendo estándares. ¡obediente! :(

EDIT:

Solo para ilustrar mi punto, considere el siguiente código:

template <typename T> void foo ( T * );
template <typename T> void foo ( T * const );
template <typename T> void foo ( T [] );
template <typename T> void foo ( T [10] );
template <typename T> void foo ( T [100] );

void bar () 
{
  foo < void() > ( 0 );
}

Aquí, foo ha sido declarado y redeclarado varias veces. ¿Qué declaración, y qué tipo de parámetro, debe el compilador aplicar las reglas enumeradas en 14.8.2?

Mi punto es que el estándar no dice nada sobre lo anterior. También me atrevería a decir que cualquier redacción sobre esto tendría que dejarlo como " undefined " o " implementación definida " comportamiento.

Otros consejos

Sorprendentemente, esto funciona en VS2008. No creo que eso sea necesariamente una evidencia de que sea un comportamiento correcto o no, aunque ...

Visual Studio está interpretando

char (&f(T[1]))[1];

como una función que toma una matriz de tamaño 1 de T y devuelve una referencia a una matriz de caracteres de tamaño 1.

Intentaré describir el proceso de deducción de argumentos de la plantilla tal como lo entiendo al leer el estándar.

  1. Los argumentos de la plantilla explícita se verifican como se describe en 14.8.2 / 2.
  2. La firma de la función resultante se ajusta de acuerdo con 8.3.5 (es decir, se realiza la caída de puntero a puntero).
  3. Los argumentos de la plantilla implícita se deducen según 14.8.2.1 (esto se realiza en una firma parcialmente sustituida en el paso 2).

La deducción por la primera sobrecarga falla en el paso 1, la resolución de sobrecarga por lo tanto devuelve la segunda sobrecarga. No creo que el programa esté mal formado.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top