Questo sito utilizza cookies, anche di terze parti, per mostrare pubblicità e servizi in linea con il tuo account. Leggi l'informativa sui cookies.
Username: Password: oppure
C/C++ - Comportamento (per me) incomprensibile d'una funzione template
Forum - C/C++ - Comportamento (per me) incomprensibile d'una funzione template

Pagine: [ 1 2 ] Precedente | Prossimo
Avatar
AldoBaldo (Member)
Expert


Messaggi: 345
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 11:52
Venerdì, 06/11/2015
Ciao a tutti.

Stavo cercando di aggiungere le funzioni template all'insieme delle mie (limitate) conoscenze, ma mi trovo di fronte a una cosa che non riesco a capire da solo. Ho già provato ad aggiungere un paio di bicchieri di buon rosso per rafforzare la capacità d'introspezione ma niente da fare -- il mistero non si dipana. :rotfl: Prima di cadere nella spirale senza fine dell'alcolismo provo a chiedere il vostro prezioso aiuto. La questione è questa...

Perché diavolo la funzione template CompattaArray() in questo codice funziona per i valori double e int e non per le stringhe const char * ?

Codice sorgente - presumibilmente C++

  1. #include <stdio.h>
  2. #include <string.h>
  3.  
  4. template <class tipo> // prototipo della funzione template
  5. unsigned int CompattaArray( tipo *a, unsigned int totEl,
  6.                             bool fNullita(tipo*),
  7.                             const tipo *nullo = NULL );
  8.  
  9. // prototipi delle funzioni di verifica
  10. // delle condizioni di nullita' (esempi)
  11. bool CondizioneNullitaPtr( const char *e );
  12. bool CondizioneNullitaDouble( double *e );
  13. bool CondizioneNullitaInt( int *e );
  14.  
  15. int main() {
  16.     const unsigned int totEl = 6;
  17.     unsigned int nElValidi = 0;
  18.  
  19.     // tutti i puntatori NULL vengono "cassati"
  20.     // gli elementi "residui" vengono annullati
  21.     const char *aPtr[totEl] = {"a","b",NULL,"c","d","e"};
  22.     const char *nPtr = NULL;
  23.     nElValidi = CompattaArray( aPtr, totEl, CondizioneNullitaPtr, &nPtr );
  24.     for( unsigned int i=0; i<totEl; ++i )
  25.         printf( "0x%08X\n", (unsigned int)aPtr[i] );
  26.     printf( "%u elementi validi\n\n", nElValidi );
  27.  
  28.     // tutti i valori inferiori a 0.5 vengono "cassati";
  29.     // gli elementi "residui" NON vengono annullati
  30.     double aDouble1[totEl] = {1.0,0.5,0.0,0.49,2.76,0.54};
  31.     nElValidi = CompattaArray( aDouble1, totEl, CondizioneNullitaDouble );
  32.     for( unsigned int i=0; i<totEl; ++i )
  33.         printf( "%f  ", aDouble1[i] );
  34.     printf( "\n%u elementi validi\n\n", nElValidi );
  35.  
  36.     // tutti i valori inferiori a 0.5 vengono "cassati";
  37.     // gli elementi "residui" vengono annullati
  38.     double aDouble2[totEl] = {1.0,0.5,0.0,0.49,2.76,0.54};
  39.     double nDouble = 0.0; // valore di annullamento double
  40.     nElValidi = CompattaArray( aDouble2, totEl, CondizioneNullitaDouble, &nDouble );
  41.     for( unsigned int i=0; i<totEl; ++i )
  42.         printf( "%f  ", aDouble2[i] );
  43.     printf( "\n%u elementi validi\n\n", nElValidi );
  44.  
  45.     // tutti i valori non compresi tra 5 e 10 vengono "cassati";
  46.     // gli elementi "residui" vengono annullati
  47.     int aInt[totEl] = {1,6,8,-2,10,11};
  48.     int nInt = 0; // valore di annullamento int
  49.     nElValidi = CompattaArray( aInt, totEl, CondizioneNullitaInt, &nInt );
  50.     for( unsigned int i=0; i<totEl; ++i )
  51.         printf( "%d  ", aInt[i] );
  52.     printf( "\n%u elementi validi\n\n", nElValidi );
  53.  
  54.     return 0;
  55. }
  56.  
  57. template <class tipo>
  58. unsigned int CompattaArray( tipo *a, unsigned int totEl,
  59.                             bool fNullita(tipo*),
  60.                             const tipo *nullo ) {
  61.     unsigned int i, j;
  62.  
  63.     for( i=j=0; i<totEl; ++i )
  64.         if( !fNullita(&(a[i])) )
  65.             a[j++] = a[i];
  66.  
  67.     if( nullo )
  68.         for( i=j; i<totEl; ++i )
  69.             a[i] = *nullo;
  70.  
  71.     return j; // la quantita' degli elementi non nulli
  72.               // "raggruppati" in testa all'array
  73. }
  74.  
  75. bool CondizioneNullitaPtr( const char *e ) {
  76.     // CompattaArray() elimina tutti i puntatori NULL
  77.     return e == NULL;
  78. }
  79.  
  80. bool CondizioneNullitaDouble( double *e ) {
  81.     // CompattaArray() elimina tutti i valori inferiori a 0.5
  82.     return *e < 0.5;
  83. }
  84.  
  85. bool CondizioneNullitaInt( int *e ) {
  86.     // CompattaArray() elimina tutti i valori non compresi tra 5 e 10
  87.     return *e < 5 || *e > 10;
  88. }



Il compilatore mastica tutto, quindi sputa fuori questa odiosa raffica di sentenze, secondo me con la chiara intenzione di denigrare i miei sforzi con una palese dose di sadismo:

||=== Build: Release in Prova fTemplate (compiler: GNU GCC Compiler) ===|
\main.cpp||In function 'int main()':|
\main.cpp|23|error: no matching function for call to 'CompattaArray(const char* [6], const unsigned int&, bool (&)(const char*), const char**)'|
\main.cpp|23|note: candidate is:|
\main.cpp|5|note: template<class tipo> unsigned int CompattaArray(tipo*, unsigned int, bool (*)(tipo*), const tipo*)|
\main.cpp|5|note:   template argument deduction/substitution failed:|
\main.cpp|23|note:   deduced conflicting types for parameter 'tipo' ('const char*' and 'const char')|
||=== Build failed: 1 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|

(Ho eliminato tutti i riferimenti al percorso del file main.cpp, per sintetizzare, tanto sono irrilevanti in questo contesto.)

Credo che la chiave possa essere in quel conflicting types for parameter 'tipo', ma non capisco da cosa possa nascere il conflitto. Il compilatore non dovrebbe sostituire "tipo" con "const char*" e accettare aPtr (l'array di stringhe const char* in main) come un puntatore ad un array di const char*, ovvero come tipo* ? Non dovrebbe valere la stessa cosa anche per nPtr? No, pare proprio di no, ma non capisco perché. Sto già versando il terzo bicchiere di rosso.


Ma cosa vuoi che ne sappia? Io ci gioco, col codice, mica ci lavoro!
PM Quote
Avatar
Roby94 (Member)
Guru


Messaggi: 1127
Iscritto: 28/12/2009

Segnala al moderatore
Postato alle 12:15
Venerdì, 06/11/2015
Se provi con un semplice puntatore a char il compilatore fa ancora storie?


La programmazione è arte... fa che i tuoi script siano degni di un museo.
PM Quote
Avatar
AldoBaldo (Member)
Expert


Messaggi: 345
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 13:35
Venerdì, 06/11/2015
Non credo che troverebbe differenze tra un puntatore che punta a un array di char e un puntatore che punta ad un array di int o di double. Le apparenze mi portano a ipotizzare che la soluzione sia nascosta da qualche parte nel modo in cui viene interpretato il puntatore che punta a un array di puntatori a (const) char...

Edit: Ho effettivamente provato, il codice che segue funziona benissimo.

Codice sorgente - presumibilmente C++

  1. #include <stdio.h>
  2. #include <string.h>
  3.  
  4. template <class tipo> // prototipo della funzione template
  5. unsigned int CompattaArray( tipo *a, unsigned int totEl,
  6.                             bool fNullita(tipo*),
  7.                             const tipo *nullo = NULL );
  8.  
  9. // prototipi delle funzioni di verifica
  10. // delle condizioni di nullita' (esempi)
  11. bool CondizioneNullitaChar( char *e );
  12.  
  13. int main() {
  14.     const unsigned int totEl = 6;
  15.     unsigned int nElValidi = 0;
  16.  
  17.     // tutti i valori non compresi tra 'c' e 'f' vengono "cassati";
  18.     // gli elementi "residui" vengono annullati
  19.     char aChar[totEl] = "acudi";
  20.     char nChar = '\0'; // valore di annullamento char
  21.     nElValidi = CompattaArray( aChar, totEl, CondizioneNullitaChar, &nChar );
  22.     printf( "%s", aChar );
  23.     printf( "\n%u elementi validi\n\n", nElValidi );
  24.        
  25.     return 0;
  26. }
  27.  
  28. template <class tipo>
  29. unsigned int CompattaArray( tipo *a, unsigned int totEl,
  30.                             bool fNullita(tipo*),
  31.                             const tipo *nullo ) {
  32.     unsigned int i, j;
  33.  
  34.     for( i=j=0; i<totEl; ++i )
  35.         if( !fNullita(&(a[i])) )
  36.             a[j++] = a[i];
  37.  
  38.     if( nullo )
  39.         for( i=j; i<totEl; ++i )
  40.             a[i] = *nullo;
  41.  
  42.     return j; // la quantita' degli elementi non nulli
  43.               // "raggruppati" in testa all'array
  44. }
  45.  
  46. bool CondizioneNullitaChar( char *e ) {
  47.     // CompattaArray() elimina tutti i valori non compresi tra 'c' e 'f'
  48.     return *e < 'c' || *e > 'f';
  49. }


Ultima modifica effettuata da AldoBaldo il 06/11/2015 alle 13:52


Ma cosa vuoi che ne sappia? Io ci gioco, col codice, mica ci lavoro!
PM Quote
Avatar
TheDarkJuster (Member)
Guru^2


Messaggi: 1452
Iscritto: 27/09/2013

Segnala al moderatore
Postato alle 13:56
Venerdì, 06/11/2015
Usi l'operatore di stringa " per un array di caratteri : che usano l'operatore '. Per fare "a", "b" to serve const char **lista non char *lista.
Inoltre specificare il numero di elementi mentre inizializzi un array è una pratica abbastanza discutibile.

PM Quote
Avatar
AldoBaldo (Member)
Expert


Messaggi: 345
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 14:12
Venerdì, 06/11/2015
Sì, sono dettagli che conosco, solo che non sempre li tengo in considerazione. Avrei effettivamente potuto scrivere così:

Codice sorgente - presumibilmente C++

  1. // tutti i valori non compresi tra 'c' e 'z' vengono "cassati";
  2. // gli elementi "residui" vengono annullati
  3. char aChar[totEl] = {'a','c','u','d','i','\0'};
  4. char nChar = '\0'; // valore di annullamento char
  5.  
  6. nElValidi = CompattaArray( aChar, totEl, CondizioneNullitaChar, &nChar );
  7.  
  8. for( unsigned int i=0; i<totEl; ++i )
  9.     if( aChar[i] != '\0' )
  10.         printf( "%c ", aChar[i] );
  11.     else printf( "\'\\0\' " );
  12.  
  13. printf( "\n%u elementi validi\n\n", nElValidi );



Nei termini dell'errore che ho illustrato originariamente non cambia nulla, non credo proprio che l'errore sia lì.

L'aggiunta esplicita della quantità degli elementi dell'array è una scelta che ho fatto perché, siccome sto "sperimentando", volevo essere sicuro di non incorrere in errori nella quantificazione degli elementi nelle varie prove.

Ultima modifica effettuata da AldoBaldo il 06/11/2015 alle 14:13


Ma cosa vuoi che ne sappia? Io ci gioco, col codice, mica ci lavoro!
PM Quote
Avatar
TheDarkJuster (Member)
Guru^2


Messaggi: 1452
Iscritto: 27/09/2013

Segnala al moderatore
Postato alle 15:44
Venerdì, 06/11/2015
Ma tu hai una funzione che accetta un puntatore, non un puntatore a puntatore.

PM Quote
Avatar
lumo (Member)
Expert


Messaggi: 413
Iscritto: 18/04/2010

Segnala al moderatore
Postato alle 22:51
Venerdì, 06/11/2015
Codice sorgente - presumibilmente C++

  1. #include <stdio.h>
  2. #include <string.h>
  3.  
  4. template <class tipo> // prototipo della funzione template
  5. unsigned int CompattaArray(tipo *a, unsigned int totEl,
  6.         bool fNullita(tipo*),
  7.         const tipo *nullo = NULL);
  8.  
  9. // prototipi delle funzioni di verifica
  10. // delle condizioni di nullita' (esempi)
  11. bool CondizioneNullitaPtr(char **e);
  12. bool CondizioneNullitaDouble(double *e);
  13. bool CondizioneNullitaInt(int *e);
  14.  
  15. int main() {
  16.         const unsigned int totEl = 6;
  17.         unsigned int nElValidi = 0;
  18.  
  19.         // tutti i puntatori NULL vengono "cassati"
  20.         // gli elementi "residui" vengono annullati
  21.         char *aPtr[totEl] = { "a","b",NULL,"c","d","e" };
  22.         char *nPtr = NULL;
  23.         nElValidi = CompattaArray(aPtr, totEl, CondizioneNullitaPtr, &nPtr);
  24.         for (unsigned int i = 0; i<totEl; ++i)
  25.                 printf("0x%08X\n", (unsigned int)aPtr[i]);
  26.         printf("%u elementi validi\n\n", nElValidi);
  27.  
  28.         // tutti i valori inferiori a 0.5 vengono "cassati";
  29.         // gli elementi "residui" NON vengono annullati
  30.         double aDouble1[totEl] = { 1.0,0.5,0.0,0.49,2.76,0.54 };
  31.         nElValidi = CompattaArray(aDouble1, totEl, CondizioneNullitaDouble);
  32.         for (unsigned int i = 0; i<totEl; ++i)
  33.                 printf("%f  ", aDouble1[i]);
  34.         printf("\n%u elementi validi\n\n", nElValidi);
  35.  
  36.         // tutti i valori inferiori a 0.5 vengono "cassati";
  37.         // gli elementi "residui" vengono annullati
  38.         double aDouble2[totEl] = { 1.0,0.5,0.0,0.49,2.76,0.54 };
  39.         double nDouble = 0.0; // valore di annullamento double
  40.         nElValidi = CompattaArray(aDouble2, totEl, CondizioneNullitaDouble, &nDouble);
  41.         for (unsigned int i = 0; i<totEl; ++i)
  42.                 printf("%f  ", aDouble2[i]);
  43.         printf("\n%u elementi validi\n\n", nElValidi);
  44.  
  45.         // tutti i valori non compresi tra 5 e 10 vengono "cassati";
  46.         // gli elementi "residui" vengono annullati
  47.         int aInt[totEl] = { 1,6,8,-2,10,11 };
  48.         int nInt = 0; // valore di annullamento int
  49.         nElValidi = CompattaArray(aInt, totEl, CondizioneNullitaInt, &nInt);
  50.         for (unsigned int i = 0; i<totEl; ++i)
  51.                 printf("%d  ", aInt[i]);
  52.         printf("\n%u elementi validi\n\n", nElValidi);
  53.         getchar();
  54.         return 0;
  55. }
  56.  
  57. template <class tipo>
  58. unsigned int CompattaArray(tipo *a, unsigned int totEl,
  59.         bool fNullita(tipo*),
  60.         const tipo *nullo) {
  61.         unsigned int i, j;
  62.  
  63.         for (i = j = 0; i<totEl; ++i)
  64.                 if (!fNullita(&a[i]))
  65.                         a[j++] = a[i];
  66.  
  67.         if (nullo)
  68.                 for (i = j; i<totEl; ++i)
  69.                         a[i] = *nullo;
  70.  
  71.         return j; // la quantita' degli elementi non nulli
  72.                           // "raggruppati" in testa all'array
  73. }
  74.  
  75. bool CondizioneNullitaPtr(char **e) {
  76.         // CompattaArray() elimina tutti i puntatori NULL
  77.         return *e == NULL;
  78. }
  79.  
  80. bool CondizioneNullitaDouble(double *e) {
  81.         // CompattaArray() elimina tutti i valori inferiori a 0.5
  82.         return *e < 0.5;
  83. }
  84.  
  85. bool CondizioneNullitaInt(int *e) {
  86.         // CompattaArray() elimina tutti i valori non compresi tra 5 e 10
  87.         return *e < 5 || *e > 10;
  88. }



P.S.: di solito le funzioni come quelle vengono passate a loro volta come parametro di template :D

PM Quote
Avatar
TheDarkJuster (Member)
Guru^2


Messaggi: 1452
Iscritto: 27/09/2013

Segnala al moderatore
Postato alle 23:20
Venerdì, 06/11/2015
Lumo hai definito la funzione condizione nullità ptr perché la funzione funzionava con  un solo puntatore e non un puntatore a puntatore?
O ci sono modifiche che mi sfuggono?

PM Quote
Avatar
AldoBaldo (Member)
Expert


Messaggi: 345
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 15:05
Sabato, 07/11/2015
Lumo, mi fai fare la figura del pirla, e me lo merito. A una funzione che accetta un puntatore a puntatore passo l'indirizzo a un puntatore "semplice" e manco me ne accorgo pur guardando, e riguardando, e riguardando ancora. Robe da chiodi. Prosciutto sugli occhi. Che vergogna! Be', me la cavo come al solito: facendo notare la firma in calce a ciascuno dei miei messaggi.

Ora funziona tutto a dovere.
Grazie davvero per la guida che mi offrite (tu e gli altri) nell'orientarmi in questo mio hobby.

P.S. Ero disperato, perché ormai avevo già finito la terza bottiglia di rosso... purtuttavia continuavo a non ricavarne nessuna illuminazione. :rotfl:
PP.SS. Non è vero, non mi sono pippato così tanto rosso... però dirlo fa tanto "colore"!

Ultima modifica effettuata da AldoBaldo il 07/11/2015 alle 15:12


Ma cosa vuoi che ne sappia? Io ci gioco, col codice, mica ci lavoro!
PM Quote
Pagine: [ 1 2 ] Precedente | Prossimo