Disminución de matriz a punteros en plantillas

4 minutos de lectura

avatar de usuario
Gunther piez

Por favor considere este código:

#include <iostream>

template<typename T>
void f(T x) {
    std::cout << sizeof(T) << '\n';
}

int main()
{
    int array[27];
    f(array);
    f<decltype(array)>(array);
}

Nota del editor: el código original utilizado typeof(array)sin embargo, esa es una extensión GCC.

Esto se imprimirá

8 (or 4)
108

En el primer caso, la matriz obviamente decae a un puntero y T se convierte en int*. En el segundo caso, T se ve obligado a int[27]. ¿Está definido el orden de implementación de descomposición/sustitución? ¿Hay una forma más elegante de forzar el tipo para int[27]? Además de usar std::vector?

  • ¿Dónde encontraste un compilador de C++ donde sizeof(int) == 1? Me sale 108 para la segunda llamada.

    – Rob Kennedy

    8 de diciembre de 2009 a las 0:12

  • Sí, por supuesto que gcc ya subió a 4 bytes 😉 Introduje un error al generar un caso de prueba.

    -Gunther Piez

    8 de diciembre de 2009 a las 0:29

  • Me sorprende que la segunda llamada se compile. No puede pasar matrices por valor en C++. [edit: Ah, T has the array type, but sizeof(x) would still output 8 or 4. Never mind. :)]

    – Carreras de ligereza en órbita

    9 mayo 2011 a las 22:00


  • Buen comentario necro 🙂 ¿Estás hojeando mis viejas preguntas? 🙂 El segundo caso es pasar la matriz como referencia, eso es lo que no reconocí cuando pregunté. Ver la respuesta aceptada

    -Gunther Piez

    9 de mayo de 2011 a las 22:12

avatar de usuario
AnT – Detengan a los UkroNazis

Usar el tipo de referencia para el parámetro

template<typename T> void f(const T& x) 
{
  std::cout << sizeof(T);
}

en cuyo caso el tipo de matriz no decaerá.

Del mismo modo, también puede evitar el deterioro en su versión original de f si especifica explícitamente el argumento de la plantilla T como un tipo de referencia a matriz

f<int (&)[27]>(array);

En su muestra de código original, forzando el argumento T tener el tipo de matriz (es decir, tipo de matriz sin referencia, usando typeof o especificando el tipo explícitamente), no evitará el decaimiento del tipo de matriz. Tiempo T en sí mismo representará el tipo de matriz (como observó), el parámetro x seguirá siendo declarado como un puntero y sizeof x seguirá evaluando el tamaño del puntero.

  • Sí, pero estoy usando sizeof(T). De todos modos, gracias por la rápida respuesta 🙂

    -Gunther Piez

    8 de diciembre de 2009 a las 0:24

El comportamiento de este código es explicado por C++14 [temp.deduct.call]:

Deducir argumentos de plantilla de una llamada de función

La deducción de argumentos de plantilla se realiza comparando cada tipo de parámetro de plantilla de función (llámelo P) con el tipo del argumento correspondiente de la llamada (llámalo A) como se describe abajo

y luego abajo:

Si P no es un tipo de referencia:

  • Si A es un tipo de matriz, el tipo de puntero producido por la conversión estándar de matriz a puntero (4.2) se usa en lugar de A para tipo deducción;

para la llamada f(array);tenemos A = int[27]. A es un tipo de matriz. Entonces el tipo deducido T es int *de acuerdo con este último punto.

Podemos ver en el calificador “Si P no es un tipo de referencia” que este comportamiento tal vez podría evitarse haciendo P un tipo de referencia. Para el código:

template<typename T, size_t N>
void f(T (&x)[N])

el símbolo P medio T(&)[N], que es un tipo de referencia; y resulta que aquí no se aplican conversiones. T se deduce a intcon el tipo de x siendo int(&)[N].


Tenga en cuenta que esto solo se aplica a las plantillas de funciones en las que el tipo se deduce del argumento. El comportamiento está cubierto por partes separadas de la especificación para los parámetros de plantilla de función y plantillas de clase proporcionados explícitamente.

También puede usar plantillas como las siguientes:

template <typename T, std::size_t N>
inline std::size_t number_of_elements(T (&ary)[N]) {
    return N;
}

Este pequeño truco causará errores de compilación si la función se usa en un tipo que no sea de matriz.

avatar de usuario
Jorge Fritzsche

Dependiendo de su caso de uso, puede solucionarlo usando referencias:

template<typename T>
void f(const T& x) {
    std::cout << sizeof(T);
}

char a[27];
f(a);

que imprime 27como se desee.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad