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++ - Template
Forum - C/C++ - Template

Pagine: [ 1 2 ] Precedente | Prossimo
Avatar
Roby94 (Member)
Guru


Messaggi: 1127
Iscritto: 28/12/2009

Segnala al moderatore
Postato alle 18:41
Lunedì, 19/10/2015
Salve, sto continuando il porting di alcune librerie da C a CPP e vorrei sfruttare al meglio i vantaggi offerti da quest'ultimo rispetto al suo predecessore. In particolare sto cercando di abbandonare l'abbondante utilizzo di funzioni che accettino in ingresso una grande varieta di tipi di parametro a favore di un piu snello template. Il problema è che sto riscontrando diversi problemi nella scrittura di una libreria statica.
Codice sorgente - presumibilmente C++

  1. #pragma once
  2.  
  3. #include <avr/io.h>
  4.  
  5. namespace EEPROM
  6. {
  7.         template <typename T> T Read(uint16_t);
  8.         template <typename T> void Read(uint16_t, T[], uint16_t);
  9.        
  10.         template <typename T> void Write(uint16_t, T);
  11.         template <typename T> void Write(uint16_t, T[], uint16_t);
  12. }


Codice sorgente - presumibilmente C++

  1. #include "EEPROM.h"
  2.  
  3. template <typename T> T EEPROM::Read(uint16_t address) {/**/}
  4. template <typename T> void EEPROM::Read(uint16_t address, T array[], uint16_t n) {/**/}
  5.  
  6. template <typename T> void EEPROM::Write(uint16_t address, T data) {/**/}
  7. template <typename T> void EEPROM::Write(uint16_t address, T array[], uint16_t n) {/**/}


Questi sono i due file della libreria rispettivamente EEPROM.h e EEPROM.cpp.
Se aggiunti ad un progetto ricevo come errore del genere
Codice sorgente - presumibilmente C/C++

  1. undefined reference to `void EEPROM::Write<unsigned int>(unsigned int, unsigned int*, unsigned int)'


Ho risolto dichiarando nel file EEPROM.cpp
Codice sorgente - presumibilmente C/C++

  1. template void EEPROM::Write(uint16_t, uint16_t[], uint16_t);


per ogni combinazione di tipi.
Tutto questo funziona finché non compilo la libreria e cerco di richiamare la medesima funzione ricevendo lo stesso errore riportato in precedenza.
Ora, io purtroppo in casa non ho un libro sul CPP, su internet inoltre non riesco a trovare una soluzione, noto che nessuno o quasi aggiunge la definizione della funzione per ogni tipo. Cosa sbaglio? Esiste un metodo piu corretto di realizzare quello di cui ho bisogno? Attualmente sto usando GCC rilasciato con Atmel Studio 7.
Vi ringrazio per ogni aiuto.

Roberto


La programmazione è arte... fa che i tuoi script siano degni di un museo.
PM Quote
Avatar
pierotofy (Admin)
Guru^2


Messaggi: 6110
Iscritto: 04/12/2003

Segnala al moderatore
Postato alle 20:15
Lunedì, 19/10/2015
Non puoi compilare la libreria in questo modo; i template vengono risolti al momento della compilazione.

Puoi includere la tua libreria inserendo il .h e .cpp nel tuo progetto, ma non puoi compilarla e poi includerla come .lib o .a (non senza dichiarare ogni combinazione di tipi, vedi qui sotto).

Vedi come fa boost. http://www.boost.org/doc/libs/1_55_0/more/getting_started/ ...

Se vuoi compilarla, devi aggiungere le definizioni per i tipi, per ogni combinazione di tipi (come hai già fatto). E' strano che non funzioni, forse se posti i sorgenti e i risultati della compilazione possiamo dirti di più.


Ultima modifica effettuata da pierotofy il 19/10/2015 alle 20:16


Seguimi su Twitter: http://www.twitter.com/pierotofy

Fai quello che ti piace, e fallo bene.
PM Quote
Avatar
Roby94 (Member)
Guru


Messaggi: 1127
Iscritto: 28/12/2009

Segnala al moderatore
Postato alle 20:30
Lunedì, 19/10/2015
Grazie piero.
Ho semplicemente aggiunto
Codice sorgente - presumibilmente C++

  1. template uint8_t EEPROM::Read(uint16_t);
  2. template uint16_t EEPROM::Read(uint16_t);
  3.  
  4. template void EEPROM::Read(uint16_t, uint8_t[], uint16_t);
  5. template void EEPROM::Read(uint16_t, uint16_t[], uint16_t);
  6.  
  7. template void EEPROM::Write(uint16_t, uint8_t);
  8. template void EEPROM::Write(uint16_t, uint16_t);
  9.  
  10. template void EEPROM::Write(uint16_t, uint8_t[], uint16_t);
  11. template void EEPROM::Write(uint16_t, uint16_t[], uint16_t);


dentro il file cpp.
Non riesco a capire cosa dovrei vedere sulla pagina da te postata...
Se volessi optare per l'inclusione manuale mi basterebbe modificare il file h eliminando i template e sostituendoli con le semplici funzioni con i tipi al posto giusto?
es
Codice sorgente - presumibilmente C/C++

  1. void EEPROM::Write(uint16_t, uint16_t[], uint16_t);


Cosi facendo si crea tantissima ridondanza, no? Cioè viene riscritta la funzione per ogni combinazione? Non riesco a trovare molte informazioni sui template, tutte le guide su internet che ho consultato o sono incomplete o imprecise.


La programmazione è arte... fa che i tuoi script siano degni di un museo.
PM Quote
Avatar
pierotofy (Admin)
Guru^2


Messaggi: 6110
Iscritto: 04/12/2003

Segnala al moderatore
Postato alle 22:17
Lunedì, 19/10/2015
Boost è una libreria che fa ampio uso dei template. Il link ti mostra come viene utilizzato il codice di boost.

Se usi la tua libreria tramite inclusione del file .h e .cpp, non serve che scrivi tutte le combinazioni; l'utente della libreria si occuperà di dichiarare i tipi che servono a lui.

Se la compili devi dichiarare tutte le combinazioni.

Se questo approccio non ti sembra adatto alla situazione, forse la scelta di usare templates non è adatta e li stai usando in maniera sbagliata (da un punto di vista di progettazione).


Seguimi su Twitter: http://www.twitter.com/pierotofy

Fai quello che ti piace, e fallo bene.
PM Quote
Avatar
Roby94 (Member)
Guru


Messaggi: 1127
Iscritto: 28/12/2009

Segnala al moderatore
Postato alle 22:52
Lunedì, 19/10/2015
Mi spiego, ho necessita di accertare in ingresso diversi tipi di variabili e in base alla loro dimensione allocare il giusto numero di byte. Posso creare una funzione per ogni tipo, e vado a richiamare da ognuna quella più elementare, quindi quella che si occupa di gestire il singolo byte, questo è l'approccio che adopererei in C. Mi è sembrato di capire che con i template posso fare lo stesso lavoro senza ridefinire uno sproposito di funzioni. Ora ho sempre necessità di compilare una libreria statica, quindi se devo andare a ridefinire i costrutti uno ad uno non è un problema ma anche cosi facendo ricevo l'errore sopra citato. Qual'è il formalismo corretto per fare questo?


La programmazione è arte... fa che i tuoi script siano degni di un museo.
PM Quote
Avatar
pierotofy (Admin)
Guru^2


Messaggi: 6110
Iscritto: 04/12/2003

Segnala al moderatore
Postato alle 23:10
Lunedì, 19/10/2015
Definisci funzioni diverse in base al tipo che stai gestendo, ad esempio:

ReadUInt8(...
ReadString(...

Ecc.

Poi internamente nella libreria puoi implementare questi metodi usando un generico Read che usa i template.

Testo quotato


se devo andare a ridefinire i costrutti uno ad uno non è un problema ma anche cosi facendo ricevo l'errore sopra citato. Qual'è il formalismo corretto per fare questo?



Strano. Difficile dire quale sia il problema se non possiamo provare a compilare il progetto.


Ultima modifica effettuata da pierotofy il 19/10/2015 alle 23:15


Seguimi su Twitter: http://www.twitter.com/pierotofy

Fai quello che ti piace, e fallo bene.
PM Quote
Avatar
Roby94 (Member)
Guru


Messaggi: 1127
Iscritto: 28/12/2009

Segnala al moderatore
Postato alle 23:28
Lunedì, 19/10/2015
Grazie mille Piero, e mi scuso se ti sto facendo faticare.
Ho sperimentato un poco e ho notato che se nel file cpp della libreria definisco i costrutti non ricevo errore. In poche parole ho aggiunto una lista del genere
Codice sorgente - presumibilmente C++

  1. template uint8_t EEPROM::Read<uint8_t>(uint16_t);
  2. template uint16_t EEPROM::Read<uint16_t>(uint16_t);
  3. template uint32_t EEPROM::Read<uint32_t>(uint16_t);
  4. template uint64_t EEPROM::Read<uint64_t>(uint16_t);
  5. template int8_t EEPROM::Read<int8_t>(uint16_t);
  6. template int16_t EEPROM::Read<int16_t>(uint16_t);
  7. template int32_t EEPROM::Read<int32_t>(uint16_t);
  8. template int64_t EEPROM::Read<int64_t>(uint16_t);
  9. template float EEPROM::Read<float>(uint16_t);
  10. template double EEPROM::Read<double>(uint16_t);


Per tutte e 4 le funzioni, è un metodo valido o sarebbe meglio implementarlo come hai suggerito tu?

Grazie ancora per l'aiuto.

Edit:
Ovviamente ora la libreria pesa ben 16kB

Ultima modifica effettuata da Roby94 il 19/10/2015 alle 23:33


La programmazione è arte... fa che i tuoi script siano degni di un museo.
PM Quote
Avatar
pierotofy (Admin)
Guru^2


Messaggi: 6110
Iscritto: 04/12/2003

Segnala al moderatore
Postato alle 0:56
Martedì, 20/10/2015
Bho, è una questione di preferenza.

Quando si tratta di una libreria esterna, preferisco avere funzioni separate invece che usare generiche. Ma questa è una preferenza personale, perchè i templates non mi piacciono un granchè.

Ultima modifica effettuata da pierotofy il 20/10/2015 alle 0:57


Seguimi su Twitter: http://www.twitter.com/pierotofy

Fai quello che ti piace, e fallo bene.
PM Quote
Avatar
Roby94 (Member)
Guru


Messaggi: 1127
Iscritto: 28/12/2009

Segnala al moderatore
Postato alle 10:49
Martedì, 20/10/2015
L'importante per adesso è avere un codice che presenta i corretti formalismi, e non sia implementato con ingenuità.
Ora provo a giocarci un po' e vedrò se la soluzione dei templare mi deluderà oppure no. Certamente avrei preferito un gestore runtime che permettesse l'inclusione della funzione una sola volta per ogni tipo, ma questo è ovviamente un limite di CPP e lo accettiamo.
Ti ringrazio Piero per l'aiuto. Buona giornata.


La programmazione è arte... fa che i tuoi script siano degni di un museo.
PM Quote
Pagine: [ 1 2 ] Precedente | Prossimo