2011-01-21 16 views
13

uso el siguiente plantilla para obtener un puntero que apunta después del último elemento de una matriz:La obtención de un puntero al final de una matriz

template <typename T, size_t n> 
T* end_of(T (&array)[n]) 
{ 
    return array + n; 
} 

Ahora me parece recordar que había algún problema con este enfoque , pero no puedo recordar lo que era Creo que tenía algo que ver con la elección de los parámetros de tipo o los parámetros de función, pero no estoy seguro. Entonces, como un control de cordura, ¿ve algún problema con el código anterior? Prueba de uso pequeño:

int test[] = {11, 19, 5, 17, 7, 3, 13, 2}; 
std::sort(test, end_of(test)); 
+0

Dado que tiene que pasar el tamaño de la matriz a la función, ¿qué está sacando realmente de esto que no podría obtener utilizando la plantilla 'array'? –

+0

@Zac: No, la función solo tiene un único parámetro. El parámetro de la plantilla 'n' se deduce automáticamente, usted acaba de decir' end_of (array) 'como se ve en el código de ejemplo. – fredoverflow

+0

En ese caso, el problema con el que se encontraría sería con las matrices dinámicas, ya que 'n' solo tendría el tamaño de una 'T' única. –

Respuesta

8

Su propuesta no se evalúa necesariamente en tiempo de compilación, depende de la optimización. El siguiente se calcula en tiempo de compilación:

template <typename T, size_t N> char (&array(T(&)[N]))[N]; 

int main() 
{ 
    int myArray[10]; 

    std::cout << sizeof array(myArray) << std::endl; 

    return 0; 
} 

Funciona mediante la creación de un tipo de matriz de carbón de leña que es el mismo número de elementos como la matriz dada. sizeof siempre devuelve el tamaño en número de caracteres.

+0

Ah, estoy bastante seguro de que ese era el problema que tenía en mente. ¡Gracias! – fredoverflow

+0

+1 por traer el problema. Técnicamente no es que no se evalúe en tiempo de compilación, sino que incluso si se evalúa en tiempo de compilación, el valor no es una constante de tiempo de compilación. –

1

También necesita una versión const. Sin embargo, hasta donde yo sé, no hay problemas reales con ese enfoque; lo veo comúnmente usado.

+1

No, el código anterior también funciona con matrices 'const'. si pasas una matriz 'const Foo [n]', entonces se deduce que 'T' es' const Foo' en lugar de 'Foo'. – fredoverflow

+1

@Fred tiene razón. Solo falla para 'end_of (A(). A);' donde 'A' se define por' struct A {int a [1]; }; '(debido a la validación y la referencia no constante), pero creo que eso no está mal, sino que es algo bueno en este caso. –

2

El único problema que veo es que si alguna vez no conoce la longitud en tiempo de compilación, su plantilla no sabrá qué poner ahí. Entonces, tendría que decir test+x o algo así, y ahora tiene dos formas diferentes de hacer lo mismo.

Personalmente prefiero usar un vector<int> y así tener end() ya definido para mí. Si alguna vez necesita la matriz, está disponible como &v[0].

+1

Normalmente, el compilador conoce el tamaño de una matriz (la única excepción es cuando la declara como externa sin proporcionar el tamaño y luego define la matriz en una unidad de traducción diferente). Ese es el objetivo de la plantilla. No puede pasar un puntero al primer elemento de una matriz a la plantilla, porque un puntero no es una matriz. – fredoverflow

+1

@chao: también puede usar 'std :: array' y tener la función' end() 'ya definida (para matrices de tamaño estático). –

+0

Entonces, para arreglos, usa 'end_of (a)', y para los punteros usa 'a + 8'? Y, por supuesto, para los contenedores STL utiliza 'a.end()' ... – cHao

Cuestiones relacionadas