2011-01-21 5 views
13

Io uso il seguente modello per ottenere un puntamento puntatore dopo l'ultimo elemento di un array:Ottenere un puntatore alla fine di un array

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

Ora mi pare di ricordare che ci fosse qualche problema con questo approccio , ma non riesco a ricordare cosa fosse. Credo che abbia avuto qualcosa con la scelta dei parametri di tipo o dei parametri di funzione, ma non ne sono sicuro. Quindi, proprio come un controllo di integrità, vedi qualche problema con il codice sopra? Test di utilizzo ridotto:

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

Dal momento che si deve passare nella dimensione della matrice alla funzione, che cosa stai davvero uscire da questa che non si poteva ottenere utilizzando il modello 'array'? –

+0

@Zac: no, la funzione ha solo un singolo parametro. Il parametro template 'n' viene dedotto automaticamente, si dice semplicemente' end_of (array) 'come si vede nel codice di esempio. – fredoverflow

+0

In questo caso, il problema che dovresti incontrare riguarda gli array dinamici poiché 'n' sarebbe solo la dimensione di un singolo' T'. –

risposta

8

La vostra proposta non è necessariamente valutata al momento della compilazione, dipende ottimizzazione. Il seguente è calcolato in fase di compilazione:

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; 
} 

Esso funziona creando un tipo di matrice di char che è lo stesso numero di elementi dell'array dato. sizeof restituisce sempre le dimensioni in numero di caratteri.

+0

Ah, sono abbastanza sicuro che questo era il problema che avevo in mente. Grazie! – fredoverflow

+0

+1 per portare il problema. Tecnicamente non è che non venga valutato in fase di compilazione, ma piuttosto che, anche se valutato in fase di compilazione, il valore non sia una costante di tempo di compilazione. –

1

È necessaria anche una versione const. Tuttavia, per quanto ne so, non ci sono problemi reali con questo approccio, lo vedo comunemente.

+1

No, il codice precedente funziona anche con gli array 'const'. se passi una matrice 'const Foo [n]', allora 'T' viene dedotto come' const Foo' invece di solo 'Foo'. – fredoverflow

+1

@Fred ha ragione. Fallisce solo per 'end_of (A(). A);' dove 'A' è definito da' struct A {int a [1]; }; '(a causa della rvalueness e del riferimento non const), ma penso che non sia male ma piuttosto una cosa buona in questo caso. –

2

L'unico problema che vedo è che se mai non si conosce la lunghezza al momento della compilazione, il modello non si sa cosa mettere in là. Quindi dovresti dire test+x o qualcosa comunque, e ora hai due modi diversi di fare la stessa cosa.

Personalmente preferirei semplicemente usare uno vector<int> e quindi avere già definito end() per me. Se hai sempre bisogno dell'array, è disponibile come &v[0].

+1

Di solito, il compilatore conosce la dimensione di un array (l'unica eccezione è quando lo si dichiara come extern senza fornire la dimensione e quindi si definisce l'array in una diversa unità di traduzione). Questo è l'intero punto del modello. Non è possibile passare un puntatore al primo elemento di una matrice sul modello, poiché un puntatore non è un array. – fredoverflow

+1

@chao: puoi anche usare 'std :: array' e avere la funzione' end() 'già definita (per array di dimensioni statiche). –

+0

Quindi, per gli array usi 'end_of (a)', e per i puntatori usi 'a + 8'? E, naturalmente, per i container STL si usa 'a.end()' ... – cHao