Newsgroup: it.comp.lang.c++
Titolo: Non avviene l'istanziazione del membro statico...

Ciao a tutti,
il seguente codice, compilato con gcc (quello di Mandrake 7.1 : non ricordo
la versione ;-) non funziona:
***********************
#include <iostream>
class RegEntry {
public:
  RegEntry( int i ) : dato(i) { cout << "RegEntry::RegEntry( int )" <<
endl; }
  RegEntry() : dato(1) { cout << "RegEntry::RegEntry()" << endl; }
  void print() const { cout << dato << endl; }
private:
  int dato;
};
template <typename T>
class C1 {
public:
  static void publish() { r.print(); }
protected:
  C1() { const RegEntry& dummy = r ; }
private:
  static const RegEntry r;
};
template <typename T>
const RegEntry C1<T>::r( 2 );
class Pluto : public C1<Pluto>
{
  public :
    Pluto() { cout << "Pluto()" << endl; }
};
int main()
{
  C1<int>::publish();
  return 0;
}
***********************
Ovviamente il risultato dovrebbe essere 2. Invece ottengo sempre 0, come se
il costruttore usato per C1::r fosse un costruttore di default creato dal
compilatore!
(Per la cronaca, questo problema nasce dal tentativo di compilare con gcc il
codice della rubrica "No limits" della newsletter #2 di Pescio )
GRAZIE per l'aiuto.
Daniele.

 la versione ;-) non funziona:
Invece compilato con il BCC55 funziona perfettamente dando come
risultato
RegEntry::RegEntry( int )
2
EMG

 };
E soprattutto che senso ha il template 


> Ma comunque il codice e' un po' "oscuro"
Hai ragione, il codice č oscuro perchč non serve a nulla! Era solo un
esempio minimale per risolvere un problema che ho trovato tentando di
implementare la seguente libreria che serve a creare un oggetto di una
classe specificata a run-time sotto forma di stringa:
(copiato cosě com'č dalla newsletter #2 di Pescio 
www.eptacom.net
 )
****************************
// CLASS.H
#ifndef CLASS__
#define CLASS__
#include <string>
#include <map>
#include <memory>
typedef void* (*FactoryMethod)() ;
class RegEntry ;
class Class
  {
  public :
    static Class forName( std::string s )
      {
      return( Class( s ) ) ;
      }
    void* newInstance() ;
  private :
    std::string name ;
    typedef std::map< std::string, FactoryMethod > FactoryMethodMap ;
    static FactoryMethodMap* fmMap ;
    friend class RegEntry ;
    static void Register( std::string s, FactoryMethod m ) ;
    Class( std::string s ) : name( s )
      {
      }
  } ;
class RegEntry
  {
  public :
    RegEntry( const char s[], FactoryMethod f )
      Class::Register( s, f ) ;
      }
  } ;
template< class T, const char S[] > class Registered
  {
  public :
    static void* newInstance()
      {
      return( new T() ) ;
      }
  protected :
    Registered()
      {
      const RegEntry& dummy = r ;
      }
  private :
    static const RegEntry r ;
  } ;
template< class T, const char S[] > const RegEntry
Registered< T, S > :: r = RegEntry( S, Registered< T, S >::newInstance ) ;
#define REG_CLASS( C ) \
char C##Name__[] = #C ; \
class C : public Registered< C, C##Name__ >
#endif
// Class.CPP
#include <assert.h>
#include "class.h"
using namespace std ;
Class :: FactoryMethodMap* Class :: fmMap ;
void* Class :: newInstance()
  {
  assert( fmMap != NULL ) ;
  FactoryMethodMap::iterator it = fmMap->find( name ) ;
  if( it != fmMap->end() )
    return( it->second() ) ;
  else
    return( 0 ) ;
  }
void Class :: Register( std::string s, FactoryMethod m )
  {
  if( fmMap == NULL )
    fmMap = new std::map< std::string, FactoryMethod > ;
    fmMap->insert( std::pair< std::string, FactoryMethod >( s, m ) ) ;
  }
// TEST.CPP
#include <iostream>
#include <typeinfo>
#include "class.h"
using namespace std ;
REG_CLASS( Pippo )
  {
  public :
    Pippo() { cout << "Pippo()" << endl ; }
  } ;
REG_CLASS( Pluto )
  {
  public :
    Pluto() { cout << "Pluto()" << endl ; }
  } ;
int main()
  {
  Class c1 = Class::forName( "Pippo" ) ;
  void* p1 = c1.newInstance() ;
  Class c2 = Class::forName( "Pluto" ) ;
  void* p2 = c2.newInstance() ;
  return( 0 ) ;
  }
**********************************************

 funzionano.
A dire la veritą in questo modo non compila nemmeno! Infatti se ci pensi il
povero compilatore trova un simbolo T e non capisce cosa sia!
GRAZIE lo stesso!
Daniele.

Daniele Pallastrelli wrote:

ovviamente mi sono sbagliato, intendevo:
 const RegEntry C1::r( 2 );

  const RegEntry C1::r( 2 );
E' vero.
Io però ho commesso un errore nel voler ricreare un esempio minimale che
riproducesse il mio problema. In realtà non posso adottare la tua soluzione,
perchè il mio "reale" problema deriva da questo tipo di codice:
*****************************
template< class T, const char S[] > class Registered
  {
  public :
    static void* newInstance()
      {
      return( new T() ) ;
      }
  private :
    static const RegEntry r ;
  } ;
template< class T, const char S[] > const RegEntry
Registered< T, S > :: r( S, Registered< T, S >::newInstance ) ;
*****************************
Capisci bene che non posso eliminare i parametri template T e S perchè sono
argomenti del costruttore.
GRAZIE mille.
Daniele.

 Registered< T, S > :: r( S, Registered< T, S >::newInstance ) ;
Scusa una domanda al volo, perche' l'array S e' parametro del template?
Ciao,
Nicola


Come, perchč? Perchč se io instanzio una classe Registered<int, "int">
voglio che il data member statico r di tipo RegEntry venga costruito col
costruttore:
r( "int", ... )
Se vuoi di seguito riporto tutto il programma. Comunque il gentilissimo C.
Pescio (autore del codice) mi ha spiegato che il gcc opera correttamente
togliendo il "const" dalla dichiarazione e definizione di r.
(dalla newsletter #2 di C. Pescio. Ricordo che potete ricevere gratuitamente
questa ottima newsletter sul C++ iscrivendovi sul sito 
www.eptacom.net
 )
***************************
// CLASS.H
#ifndef CLASS__
#define CLASS__

typedef void* (*FactoryMethod)() ;
class RegEntry ;



template< class T, const char S[] > class Registered
  {
  public :
    static void* newInstance()
      {
      return( new T() ) ;
      }
  protected :
    Registered()
      {
      const RegEntry& dummy = r ;
      }
  private :
    static const RegEntry r ;
  } ;
template< class T, const char S[] > const RegEntry
