Newsgroup: it.comp.lang.c++
Titolo: Friend e template

Ciao,
qual e' la giusta sintassi per dichiarare:
- un template essere friend di una classe A
- una funzione membro di una classe B essere friend di una class A,
  con la classe B definita dopo la classe A.
Grazie

  con la classe B definita dopo la classe A.
Questo non è possibile perchè non puoi utilizzare la dichiarazione 
anticipata di B.
class B;
class A{
 public:
  friend void B::f(A& a); //questo genera errore: la dichiarazione 
anticipata vale solo nel caso di utilizzo di B* o B&. Negli altri casi hai 
bisogno di sapere prima la definizione di B.
 private:
  int x;
};
class B {
 int sz;
 public:
  B() {}
  void f(A& a);
};
void B::f(A& a) {
 a.x = 0;
}
Inoltre una funzione friend non può essere neppure dichiarata extern o 
static. L'unico modo che vedo possibile è quello di definire prima la classe 
B poi la classe A.
Bye
Andrea

 };
Ciao,
grazie per entrambe le risposte, ma in questo (con g++) non mi viene accettata.
b.cpp:13: error: `struct Template' redeclared as different kind of symbol
b.cpp:2:  error: previous declaration of `template<class T> class Template'
Riprovando un po' ho scoperto che funziona un:
template <class T> friend class Template;

 ma in questo (con g++) non mi viene accettata.
Si, purtroppo infatti dipende dal compilatore che usi: .NET e VC++ 6 non 
hanno problemi a capire quella sintassi.
Col gcc oltre alla sintassi che hai indicato tu, hai anche questa 
alternativa:
class T;
class A {
 public:
   friend class Template<T>;
 private:
     int x;
};
Bye
Andrea


 };
Se invece io volessi indicare una classe Friend che sia un 
template, come fa la classe che concede la friendness e 
l'amicizia a sapere a quale specializzazione del template 
concederla, a meno che non sia essa stessa una classe template ?
Mi spiego con un esempio
template <class T> class TemplAmicoOspitato;
template <class X> class TemplOspitanteAmico{
  public:
    friend class TemplAmicoOspitato<X>;
//etc
};
questo mi torna, poichè è un TIPO specifico ad essere amico di 
un oggetto di classe template
ma in :
template <class T> class TemplAmicoOspitato;
class NONTemplOspitanteAmico{
  public:
    friend class TemplAmicoOspitato<X>;
//etc
};
come fa il compilatore a capire che genere di tipo è X, a meno 
che non sia un tipo fisso e non parametrico ... cosa che non da 
molta flessibilità al costrutto.
Altra esigenza, ammettendo che una classe (NON template essa 
stessa o SI, è ininfluente) voglia concedere amicizia ed accesso 
all'intera superfamiglia dei template e non a specializzazioni 
particolari, come si potrebbe dichiarare ?
Se mi limito a dire :
class NONTemplOspitanteAmico{
  public:
    friend class TemplAmicoOspitato;
//etc
};
Mi cazzia (giustamente) poiché sto tentando di ridefinire la 
classe parametrica TemplAmicoOspitato come NON template.
Che altra sintassi si può usare per dire che tutte le 
specializzazioni sono friend con un'unica dichiarazione ?
Servirebbe qualcosa come
class NONTemplOspitanteAmico{
  public:
    friend class TemplAmicoOspitato<>;
//etc
};
Ma non ho provato se accetta un template vuoto ... penso di no.
Grazie di ogni chiarimento
ciao
Soviet-Mario


 Ma non ho provato se accetta un template vuoto ... penso di no.
La sintassi "template <>" viene usata per le specializzazioni esplicite e 
non mi risulta significhi template che accetta qualsiasi tipo :o)
Un'alternativa a volte utile è questa:
template< class X > class TemplAmicoOspitato;
class NONTemplOspitanteAmico{
 public:
    friend class TemplAmicoOspitato<int>;
    friend class TemplAmicoOspitato<double>;
    friend class TemplAmicoOspitato<char>;
    //ecc...espliciti tutti i tipi per cui il template è friend
   private:
     int x ;
 };
Può essere utile quando sai di sicuro quali sono i tipi su cui può essere 
istanziato TemplAmicoOspitato oppure quando vuoi restringere il cerchio di 
"tipi friend".
Bye
Andrea

 };
Questa è una cosa diversa: non si sta dichiarando un template friend
ma una sua ben specifica istanza, Template<T> che è una classe.
Barone Frankenstein

 
CUTTONE

 ma una sua ben specifica istanza, Template<T> che è una classe.
Ok
Bye Andrea 

Andrea Cacciarru ha scritto:


No, direi che hai maturato questa convizione guardando agli header
distribuiti con VC++ 6, che sono il risultato degli sforzi sovrumani
del buon J. Plauger per ottenere una STL che VC++ 6 riuscisse a 
compilare. Per controprova, qui
 
http://www.comeaucomputing.com/tryitout/
si può provare il compilatore Comeau, uno tra i più aderenti
allo standard (basato, come molti dei migliori, sul front end EDG)
e inserendo il seguente frammento:
   template <class T> struct Tumplate;
   struct Z {
     friend class Tumplate;
     int x;
   };
   int main() {
     Z z;
   }
segnala che "Tumplate" è già stato dichiarato e quindi la friend non
ha modo di ridichiarare la *classe* che è il comportamento richiesto
a norma di standard dalla dichiarazione
   friend class Qualcosa;
e riflettendoci un attimo ha senso: in parecchie circostanze C++ non
fa lo sforzo di "indovinare" le intenzioni del programmatore, ma si
limita a segnalare le incongruenze - ciò segna la differenza tra un
linguaggio pensato per progetti software di grosse dimensioni e VB.
Se il comportamento standard di C++ fosse quello di VC++ 6, il 
significato del seguente frammento di codice
   #include "qualcosa.h"
   struct Z {
     friend class Tumplate;
     int x;
   };
dipenderebbe da come è stato definito "Tumplate", introducendo una
nociva "azione a distanza" in cui un intervento innocente in un punto
causa guai in un punto diverso (non che in C++ non ce ne siano altre,
ma almeno le più ovvie si è cercato di prevenirle: "export" pare che
da questo punto di vista sia stato un fiasco, comunque).
Invece che provare a indovinare, il compilatore affronta la cosa in modo
assiomatico: la dichiarazione deve avere sempre lo stesso senso 
indipendentemente dal contesto, quella è la sintassi per dichiarare una
classe friend, eventualmente iniettata nel namespace contenente la 
classe, quindi "Tumplate" è una classe oppure c'è un errore.
Barone Frankenstein