Newsgroup: it.comp.lang.c++
Titolo: matrice con stl

ciao a tutti
per la tesi mi e' stato chiesto di implementare una classe matrice
usando le 
stl.la
 mia idea e'di vederle come vettore di vettori:ho
definito un header,l'implementazione (dei soli costruttori) e sono
gia'nelle canne! infatti finche'invoco il costruttore generico
matrix<int>() va' tutto bene (almeno sembra...), quando provo a chiamare
matrix<int>(int numrighe,int numcolonne) il compilatore (g++ sotto
linux) non mi vede il costruttore. il codice mi sembra giusto (l'ho
controllato col relatore e con altri ragazzi),e non so' piu' dove
sbattere la testa. sperando di essere stato chiaro ringrazio gia' chi mi
rispondera'.
-- 
Ciao,Marcello   
ig...@dist.unige.it

 linux) non mi vede il costruttore. 
Credo che mostrassi qualche frammento rilevante del codice sarebbe più
facile azzardare qualche spiegazione. Una classe matrice io la
implementerei più o meno così così:
 template < class T >
 class matrice
 {
      vector< vector<T> >	data;
      public:
      matrix( int righe, int col ) : data( righe, vector<T>( col, 0 ))
      { 
      }
      // etc...
 }
Max

 facile azzardare qualche spiegazione.
beh in effetti mi scocciava fare un post di 2km, pero' cosi' sono stato
poco chiaro!
ecco il codice (nell' header ho solo le dichiarazioni)
template <class T,int a,int b> 
matrix<T,a,b>::matrix(int a,int b)
{
  nrows=a;
  ncolumns=b;
  vector<T> mrow[ncolumns]; // riga=vettore lungo numcolumns
  vector< vector<T> > mmatr[nrows]; //matrice = vett di vett
 
  for(int i=0;i<ncolumns;i++)
    mmatr[i]=mrow; // ogni riga = al vettore riga (non tipo)
 
};
ho fatto anche un costruttore matrix() che assegna a nrows e ncolumns il
valore 1.(per il cod. l'ho incollato). il problema e' che quando da un
test.cpp chiamo un oggetto
matrix<int> pippo(); 
va' tutto ok, quando provo a definire
matrix<int>pippo(2,3);
salta tutto!
Ancora due cose: nell'header ho definito il template come 
template<class T, int a=1,int b=1>
Inoltre questa e' una seconda versione:nella prima nel template c'era
solo class T, cioe' provavo a passare le dimensioni solo dal
costruttore, come mi sembra tu mi stia suggerendo, ma il problema
rimaneva. Il compilatore (g++) mi dice che la variabile pippo non e'
usata (e quindi la vede),e poi mi parla di 'undefined reference to
matrix<int,1,1>::matrix(int,int)'
da notare che costruisco pippo con i valori 2 e 3 e legge 1 e 1,che sono
i default
ancora grazie
-- 
Ciao,Marcello   
ig...@dist.unige.it

 wrote in message
news:393CA522...@dist.unige.it...
    > Credo che mostrassi qualche frammento rilevante del codice sarebbe piů
    > facile azzardare qualche spiegazione.
    beh in effetti mi scocciava fare un post di 2km, pero' cosi' sono stato
    poco chiaro!
    ecco il codice (nell' header ho solo le dichiarazioni)
    template <class T,int a,int b>
    matrix<T,a,b>::matrix(int a,int b)
E` certamente un errore usare i parametri a e b sia come parametri di
template sia come argomenti del costruttore!
    ho fatto anche un costruttore matrix() che assegna a nrows e ncolumns il
    valore 1.(per il cod. l'ho incollato). il problema e' che quando da un
    test.cpp chiamo un oggetto
    matrix<int> pippo();
    va' tutto ok, quando provo a definire
Ma come e` parametrizzata la classe-template matrix?  Con un solo
parametro, il tipo T, o con 3, T seguito da due costanti intere?!
Inoltre qui stai dichiarando una FUNZIONE pippo, che non prende
nessun argomento e torna per valore una matrix<int>.  La confusione
mi sembra quindi totale.
Se il template ha 3 parametri non si capisce come il compilatore
possa qui accettarne l'istanziazione con uno solo!  Hai forse dei
default?
    matrix<int>pippo(2,3);
    salta tutto!
    Ancora due cose: nell'header ho definito il template come
    template<class T, int a=1,int b=1>
Aha, OK.  Il tuo problema e` nella confusione fra i ruoli dei
parametri dei template (fissati come costanti compile-time) e
degli argomenti dei costruttori (determinati invece a runtime).
Decidi: matrix ha le dimensioni come costanti compile-time,
per cui una data matrice nasce con certe dimensioni note gia`
alla compilazione e cosi` resta; oppure sono determinate a
run-time, passate al costruttore, e (se occorre) magari anche
cambiate piu` avanti?  O l'una, o l'altra.  La seconda scelta
da` maggiore flessibilita`, anche se la prima ha potenzialmente
una maggiore prestazione (velocita`).
Se scegli i parametri di template, dichiarerai ad esempio
    matrix<int, 2, 3> pippo;
SENZA () fra pippo e il ; nota bene, se no non e` una
variabile, ma una funzione!  E userai sempre e solo il
costruttore che non accetta argomenti (default ctor).
Se scegli gli argomenti al costruttore, togli i due
parametri a e b dal template di matrix, e dichiarerai
    matrix<int> pippo(2,3);
Alex

 Alex
mamma mia divento matto: non va! (tra l'altro e' la prima cosa che ho
fatto,ma non vedo lo sbaglio).copio l'header ed i file:
dall'header:
template <class T>
class matrix {
  int nrows;
  int ncolumns;
  typedef vector <T> row;
  typedef vector <row> matr; //inutile xche' non usata
 public:
  //CSTR
  matrix(int a,int b);
  matrix();
  matrix(int a);
  matrix(const matrix&);
 
  //DSTR
  //~matrix(){};
e questo e' il codice:
template <class T>
matrix<T>::matrix(int a,int b)
{
  nrows=a;
  ncolumns=b;
  vector<T> mrow[ncolumns]; 
  vector< vector<T> > mmatr[nrows]; 
  for(int i=0;i<ncolumns;i++)
    mmatr[i]=mrow; // ogni riga = al vettore riga (non tipo)
 
};
template <class T>
matrix<T>::matrix()
{
  nrows=1;
  ncolumns=1;
  vector<T> mrow[ncolumns]; // riga=vettore lungo numcolumns
  vector< vector<T> > mmatr[nrows]; //matrice = vett di vett
 
  for(int i=0;i<nrows;i++)
    mmatr[i]=mrow; // ogni riga = al vettore riga (non tipo)
};
infine in test.cpp chiamo:
  const int c=2;
  const int d=2;
  cout << "c=" << c << endl;
 
  matrix<int> pippo;
  matrix<int> pluto(c,d);
 
compilo e leggo undefined reference to matrix<int>::matrix(void)
 e idem per pluto   (con int int)
arigrazie..
-- 
Ciao,Marcello   
ig...@dist.unige.it

   vector< vector<T> > mmatr[nrows]; 
Qui invece un array di vettori di vettori. Se usi vector dimenticati gli
array.
Scusa, ma il codice che ti ho suggerito faceva così schifo?
Andiamo per ordine. 
Per prima cosa io definirei un membro di questo tipo
  vector< vector<T> >	m_data;
Questo oggetto ha già tutto quello che serve per modellare una matrice e,
a condizione che sia opportunamente inizializzato, può essere manipolato
con la sintassi classica degli array:
 m_data[ 10 ][ 23 ] = qualcosa ;
Ora prepariamo il costrutttore che inizializza opportunamente il membro
m_data in base ai parametri specificati:
  template< class T >
  matrix::matrix( int cols, int rows, const T& val ) ://initialization-list!
  // vector<T> ha un costruttore con due  argomenti: dimensione e default
	m_data( cols, vector<T>( rows, val ) ) 
                   // uso oggetto temporaneo per inizializzare il vector
  {
  }  // body vuoto
Poi per consentire l'accesso con la sintassi degli array definisco
opportunamento operator[]:
  vector<T>& operator[]( int i ) { return m_data[ i ]; }
Ora posso scrivere:
   matrix<int>	m( 10, 10, 0 );
   m[1][1] = 300;
Max

> Scusa, ma il codice che ti ho suggerito faceva così schifo?
assolutamente no! e' che avendo iniziato da poco,cercavo di capire i
miei errori (che si sono rivelati vere lacune!)
avevo gia' deciso di utilizzarlo
lo provo subito,e nel caso di problemi so' dove rivolgermi... :-)
grazie ancora
-- 
Ciao,Marcello   
ig...@dist.unige.it

   vector< vector<T> > mmatr[nrows]; file://matrice = vett di vett


 Presumibilmente, il tuo compilatore non lo trova.  Mettilo nel .h e dicci...
innanzitutto mi scuso per il ritardo della risposta,ma il msg mi e'
arrivato solo ora (15.45)
finalmente sembra funzionare!!!
ho copiato il codice suggeritomi da Max M. (che tra l'altro ha un
errore: quando dichiaro il costruttore devo mettere matrix<T>:: ecc.,
chiaramente lo dico per chi fosse interessato e non per riprendere ;-) )
e tutto funziona.
il problema era che mettevo "il codice" in un file matrix.cpp,e non
nell'header.
lo facevo perche' pensavo che fosse una soluzione piu' elegante ed
object oriented (separare l'interfaccia dall'implementazione).
sinceramente non ho capito perche',ma funziona solo col codice
nell'header. se qualcuno ha voglia di spiegarmi il perche' lo ringrazio
gia' ora,in ogni caso rileggero' per l'ennesima volta il cap di b.eckel,
visto che mi sembra di aver rotto le palle abbastanza...
avendo un bel simulatore da creare,mi sa' che ci sentiremo ancora.
grazie
-- 
Ciao,Marcello   
ig...@dist.unige.it

 nell'header. se qualcuno ha voglia di spiegarmi il perche' lo ringrazio
Dipende tutto dal tuo compilatore: se ha o meno il modo (schema
o convenzione che sia) di trovare il codice dei tuoi template
quando gli serve.  IBM Visual Age C++ ad esempio lo fa tenendo
tutto il codice in un suo DB, ma i programmatori, pare, non
tollerano l'idea che il codice non sia invece in normali file
di testo.  Vecchi compilatori C++ lo facevano per convenzione
(tutti i metodi della classe template X devono stare nel file
chiamato X nel directory chiamato Y) e anche quella e` rottura
non da poco.
Alex

 non da poco.
uso il g++ (la versione della suse,dovrebbe essere recente). ma questo
tipo di problema non dovrebbe risolversi con la creazione di file
oggetto .o successivamente linkati?
-- 
Ciao,Marcello   
ig...@dist.unige.it

 wrote in message
news:393DF5AD...@dist.unige.it...

Il problema non e` se le istanziazioni automatiche dei template
vadano in .o separati o nello stesso .o dove si usano (magari col
linker che poi elimina i duplicati, come fa oggi quello Microsoft),
e` come fa il compilatore a generare quel codice: a questo scopo
ha evidentemente bisogno di accedere ai SORGENTI del template.
Mi pare che per il g++ si possa usare uno switch --frepo che
usa all'uopo un certo schema convenzionale.  Era abbastanza
sperimentale quando usavo il g++ per lavoro, qualche anno fa,
ma spero che si sia consolidato.  Comunque, all'epoca, noi
decidemmo di non farne uso perche` rallentava eccessivamente
la compilazione (ma, certo, erano macchine molto piu` lente
di quelle di oggi!).
Alex

 
No. Le funzioni e le classi template vengono instanziate in fase di
compilazione. Le informazioni per instanziarle sono nel codice sorgente. A
meno che tu non richieda qualche esplicita instanziazione nel file .cpp,
il file oggetto prodotto non sarà di alcuna utilità.
Max