2011-10-17 10 views
6

Non capisco perché l'array decada in un puntatore in una funzione modello.perché l'array decade in un puntatore in una funzione modello

Se si guarda il seguente codice: Quando il parametro è forzato a essere un riferimento (funzione f1) non decadono. Nell'altra funzione, decade. Perché il tipo di T nella funzione f non è const char (buff &) [3] ma piuttosto const char * (se ho capito bene)?

#include <iostream> 

template <class T> 
void f(T buff) { 
    std::cout << "f:buff size:" << sizeof(buff) << std::endl;  //prints 4 
} 

template <class T> 
void f1(T& buff) { 
    std::cout << "f:buff size:" << sizeof(buff) << std::endl;  //prints 3 
} 

int main(int argc, char *argv[]) { 
    const char buff[3] = {0,0,0}; 
    std::cout << "buff size:" << sizeof(buff) << std::endl;   //prints 3 
    f(buff); 
    f1(buff); 
    return 0; 
} 
+0

Se hai semplicemente passato un 'in t' a 'f', quindi' T' sarebbe 'int', non' int & '. Pertanto, dovresti chiedere qualcosa del tipo "Perché il tipo di T nella funzione f non è' const char [3] 'ma piuttosto' const char * '?" (notare la mancanza '&' rispetto alla risposta) –

+0

... (seguire il mio ultimo commento). La cosa più stupida del linguaggio C/C++ è che se metti 'const char [3]' nei tuoi parametri, il compilatore lo riscriverà in modo silenzioso come 'const char *'. Questo non succede con le variabili locali, per esempio. Penso davvero che questo dovrebbe portare ad avvertimenti al giorno d'oggi (dai compilatori C++ almeno) –

risposta

7

Poiché gli array non possono essere passati per valore come parametro di funzione.
Quando li passi per valore decadono in un puntatore.

In questa funzione:

template <class T> 
void f(T buff) { 

T non può essere char (&buff)[3] quanto questo è un riferimento. Il compilatore avrebbe provato a passare char (buff)[3] per valore ma ciò non è consentito. Quindi, per farlo funzionare, gli array si decompongono a puntatori.

La seconda funzione funziona perché qui la matrice viene passata per riferimento:

template <class T> 
void f1(T& buff) { 

// Here T& => char (&buff)[3] 
+0

Credo che il motivo per cui non possono essere passati per valore è legato alla mancanza di copia/assegnazione. (Anche se questo è tutto ciò che manca è oltre me) –

+0

@MooingDuck: In C++ il motivo è che il comportamento particolare è stato ereditato da C. In C il motivo sarebbe diverso, ovviamente ... –

+1

@MooingDuck: E ovviamente questo è uno delle cose che rendono 'std :: array <>' immediatamente superiore agli array C grezzi. – ildjarn

1

Poiché le funzioni non possono avere matrici come argomenti. Tuttavia possono avere riferimenti di array.

1

Il motivo si riduce fondamentalmente alla detrazione del tipo quando si confrontano i diversi sovraccarichi. Quando si chiama f il compilatore deduce il tipo da che decade in const char* perché è ciò che gli array fanno. Questo viene fatto nello stesso modo in cui nel f(1) il compilatore deduce T come int e non int&.

Nel caso di f1 poiché l'argomento è preso come riferimento, il compilatore deduce nuovamente T per essere const char[3], ma prende un riferimento ad esso.

Niente di veramente sorprendente, ma piuttosto consistente, se non fosse per il decadimento di array di puntatori quando viene utilizzato come argomenti della funzione ...

0

In f1(), Dimensioni 4 è la dimensione del puntatore, che è di 4 byte. perché in questa funzione hai un puntatore all'array.

In f1(), si dispone di quell'array per riferimento (o un altro nome) e si tratta di dimensioni di array reali.

4

Per citare spec, si dice

(14.8.2.1/2) Se P non è un tipo di riferimento: - Se A è un tipo di matrice, il tipo di puntatore prodotta dalla matrice-to - la conversione standard del contatore (4.2) è utilizzata al posto di A per la deduzione del tipo; altrimenti

Quindi, nel tuo caso, è chiaro che,

template <class T> 
void f1(T& buff) { 
    std::cout << "f:buff size:" << sizeof(buff) << std::endl;  //prints 3 
} 

non decade in puntatore.

5

È perché gli array non possono essere superati in base al valore in una funzione. Quindi, per farlo funzionare, l'array decade in un puntatore che poi viene passato alla funzione dal valore.

In altre parole, passando una matrice per valore è simile a inizializzazione una matrice con un'altra matrice, ma in C++ un array non può essere inizializzato con un altro array:

char buff[3] = {0,0,0}; 
char x[3] = buff; //error 

Quindi, se appare una matrice sul lato destro della =, lato sinistro deve essere o pointer o reference tipo:

char *y = buff; //ok - pointer 
char (&z)[3] = buff; //ok - reference 

Dimostrazione: http://www.ideone.com/BlfSv

È esattamente per la stessa ragione auto è dedotto diverso in ogni caso al di sotto (notare che auto viene fornito con C++ 11):

auto a = buff; //a is a pointer - a is same as y (above) 
std::cout << sizeof(a) << std::endl; //sizeof(a) == sizeof(char*) 

auto & b = buff; //b is a reference to the array - b is same as z (above) 
std::cout << sizeof(b) << std::endl; //sizeof(b) == sizeof(char[3]) 

uscita:

4 //size of the pointer 
3 //size of the array of 3 chars 

Demo: http://www.ideone.com/aXcF5

Problemi correlati