473,729 Members | 2,359 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Instantiation of static variable in template class fails, why??


Hi, I really need some help here. After upgrading to g++ 3.4 I have run
into all sorts of troubles that I'm sure depends on my lack of proper
understanding of C++. I would now like to get it right once and for all,
if possible.

Most severe is the problem illustrated by the code below. It's based on
the "pluggable factory pattern" described in

http://www.adtmag.com/joop/crarticle.asp?ID=1520

It's a generic factory class using templates to ease the addition of new
types to the hierarchy.

The code below is a simplified version of the system we use. It compiles
and runs fine and dandy with g++ 3.3.3, whereas 3.4.2 gives the error
message "too few template-parameter-lists". If I uncomment the
commented lines below (//template <>) both versions compile the code but
neither run properly - no output is produced. It has something to
do with instantiation of static members in template classes, AFAIU.
Expected output from the program is

DataTypeA
DataTypeB

Could someone please help me understand what's going on here? I'd be very
grateful. Code and some output below.

Thanks,
Erik

Successful run with g++ 3.3.3:

bash$ g++ -c main.cc
bash$ g++ -c generalmaker.cc
bash$ g++ -c typeAmaker.cc
bash$ g++ -c typeBmaker.cc
bash$ g++ -o makertest main.o generalmaker.o typeAmaker.o typeBmaker.o
bash$ ./makertest
DataTypeA
DataTypeB
bash$

Code:

-----8<-----
//main.cc

#include <iostream>
#include "generalmaker.h "
#include <string>
#include <list>

using namespace std;

int main() {

list<string> typelist = GeneralMaker::l istRegistered() ;

for( list<string>::i terator it = typelist.begin( ); it != typelist.end(); ++it ) {
cerr<<*it<<endl ;
}

return 0;
}

-----8<-----
//generalmaker.h

#ifndef GENERALMAKER_H
#define GENERALMAKER_H

#include <map>
#include <string>
#include <list>

class GeneralData;

class GeneralMaker
{
public:
virtual ~GeneralMaker() {}
static GeneralData * newData( const std::string& );
static std::list<std:: string> listRegistered( );
protected:
GeneralMaker( ) {}
virtual GeneralData* makeData() = 0;
typedef std::map< std::string , GeneralMaker * > MakerMap;
static MakerMap & registry();

};

template <class Data, const char * str_>
class GeneralMakerTP : public GeneralMaker
{
protected:
GeneralMakerTP( ) : GeneralMaker( )
{
Data d;
std::string str = d.uniqueName();
GeneralMaker::r egistry().inser t( make_pair( str, this ) );
}
GeneralData* makeData()
{
return new Data();
}
static const GeneralMakerTP< Data, str_> registerThis;
};

#endif

-----8<-----
//generalmaker.cc

#include "generalmaker.h "
#include "generaldat a.h"

using namespace std;

list<string> GeneralMaker::l istRegistered()
{
list<string> list;

for ( MakerMap::const _iterator it = registry().begi n(); it != registry().end( ); ++it )
{
list.push_back( it->first );
}
return list;
}

GeneralMaker::M akerMap & GeneralMaker::r egistry()
{
/* We use this because static instances of sub classes of GeneralMaker
make use of this map. The idea comes from c++ faq lite
[10.12] How do I prevent the "static initialization order fiasco"?
*/

static GeneralMaker::M akerMap reg;
return reg;
}

GeneralData* GeneralMaker::n ewData( const std::string& generalDataType )
{
GeneralMaker* maker =
(*registry().fi nd( generalDataType )).second;
return maker ? maker->makeData() : NULL;
}

-----8<-----
//generaldata.h

#ifndef GENERALDATA_H
#define GENERALDATA_H

#include <string>
#include "generalmaker.h "
#include "generaldat a.h"
class GeneralData
{
public:
GeneralData() {}
virtual ~GeneralData(){ }

virtual std::string uniqueName() = 0;

};

#endif

-----8<-----
//datatypeA.h

#ifndef DATATYPEA_H
#define DATATYPEA_H

#include "generaldat a.h"
#include <string>

class DataTypeA : public GeneralData
{
public:
DataTypeA( ) : GeneralData() {}
~DataTypeA() {}
std::string uniqueName() { return std::string("Da taTypeA"); }

};

#endif

-----8<-----
//datatypeB.h

#ifndef DATATYPEB_H
#define DATATYPEB_H

#include "generaldat a.h"
#include <string>

class DataTypeB : public GeneralData
{
public:
DataTypeB( ) : GeneralData() {}
~DataTypeB() {}
std::string uniqueName() { return std::string("Da taTypeB"); }

};

#endif

-----8<-----
//typeAmaker.cc

#include "datatypeA. h"
#include "generalmaker.h "

char nameA[] = "DataTypeA" ;
//template<> //If I uncomment this, g++ 3.4 compiles but runs incorrectly
const GeneralMakerTP< DataTypeA, nameA> GeneralMakerTP< DataTypeA,nameA >::registerThis ;

-----8<-----
//typeBmaker.cc

#include "datatypeB. h"
#include "generalmaker.h "

char nameB[] = "DataTypeB" ;
//template<> //If I uncomment this, g++ 3.4 compiles but runs incorrectly
const GeneralMakerTP< DataTypeB, nameB> GeneralMakerTP< DataTypeB,nameB >::registerThis ;
--
My Hotmail address is a spam magnet. If replying by email,
please use erik dot arner at cgb dot ki dot se

Jul 22 '05 #1
18 5760
Maybe (and I dont claim to be a guru) templates are generated code and
static members cause ambiguity, because they need to be specifically called
and 'typed'.
I had same problem and once I found a way around it, all hell came loose
when I tried to import/export.
So I removed the static members from the template and I called them in the
derived classes of the template
for example
class MyDerivedFromTe mplate : public YourTemplate< SomeClass >
{
static int s_number_of_obj ects;
.....
};

hope this helps.

"Erik Arner" <er********@hot mail.com> wrote in message
news:pa******** *************** *****@hotmail.c om...

Hi, I really need some help here. After upgrading to g++ 3.4 I have run
into all sorts of troubles that I'm sure depends on my lack of proper
understanding of C++. I would now like to get it right once and for all,
if possible.

Most severe is the problem illustrated by the code below. It's based on
the "pluggable factory pattern" described in

http://www.adtmag.com/joop/crarticle.asp?ID=1520

It's a generic factory class using templates to ease the addition of new
types to the hierarchy.

The code below is a simplified version of the system we use. It compiles
and runs fine and dandy with g++ 3.3.3, whereas 3.4.2 gives the error
message "too few template-parameter-lists". If I uncomment the
commented lines below (//template <>) both versions compile the code but
neither run properly - no output is produced. It has something to
do with instantiation of static members in template classes, AFAIU.
Expected output from the program is

DataTypeA
DataTypeB

Could someone please help me understand what's going on here? I'd be very
grateful. Code and some output below.

Thanks,
Erik

Successful run with g++ 3.3.3:

bash$ g++ -c main.cc
bash$ g++ -c generalmaker.cc
bash$ g++ -c typeAmaker.cc
bash$ g++ -c typeBmaker.cc
bash$ g++ -o makertest main.o generalmaker.o typeAmaker.o typeBmaker.o
bash$ ./makertest
DataTypeA
DataTypeB
bash$

Code:

-----8<-----
//main.cc

#include <iostream>
#include "generalmaker.h "
#include <string>
#include <list>

using namespace std;

int main() {

list<string> typelist = GeneralMaker::l istRegistered() ;

for( list<string>::i terator it = typelist.begin( ); it != typelist.end();
++it ) {
cerr<<*it<<endl ;
}

return 0;
}

-----8<-----
//generalmaker.h

#ifndef GENERALMAKER_H
#define GENERALMAKER_H

#include <map>
#include <string>
#include <list>

class GeneralData;

class GeneralMaker
{
public:
virtual ~GeneralMaker() {}
static GeneralData * newData( const std::string& );
static std::list<std:: string> listRegistered( );
protected:
GeneralMaker( ) {}
virtual GeneralData* makeData() = 0;
typedef std::map< std::string , GeneralMaker * > MakerMap;
static MakerMap & registry();

};

template <class Data, const char * str_>
class GeneralMakerTP : public GeneralMaker
{
protected:
GeneralMakerTP( ) : GeneralMaker( )
{
Data d;
std::string str = d.uniqueName();
GeneralMaker::r egistry().inser t( make_pair( str, this ) );
}
GeneralData* makeData()
{
return new Data();
}
static const GeneralMakerTP< Data, str_> registerThis;
};

#endif

-----8<-----
//generalmaker.cc

#include "generalmaker.h "
#include "generaldat a.h"

using namespace std;

list<string> GeneralMaker::l istRegistered()
{
list<string> list;

for ( MakerMap::const _iterator it = registry().begi n(); it !=
registry().end( ); ++it )
{
list.push_back( it->first );
}
return list;
}

GeneralMaker::M akerMap & GeneralMaker::r egistry()
{
/* We use this because static instances of sub classes of GeneralMaker
make use of this map. The idea comes from c++ faq lite
[10.12] How do I prevent the "static initialization order fiasco"?
*/

static GeneralMaker::M akerMap reg;
return reg;
}

GeneralData* GeneralMaker::n ewData( const std::string& generalDataType )
{
GeneralMaker* maker =
(*registry().fi nd( generalDataType )).second;
return maker ? maker->makeData() : NULL;
}

-----8<-----
//generaldata.h

#ifndef GENERALDATA_H
#define GENERALDATA_H

#include <string>
#include "generalmaker.h "
#include "generaldat a.h"
class GeneralData
{
public:
GeneralData() {}
virtual ~GeneralData(){ }

virtual std::string uniqueName() = 0;

};

#endif

-----8<-----
//datatypeA.h

#ifndef DATATYPEA_H
#define DATATYPEA_H

#include "generaldat a.h"
#include <string>

class DataTypeA : public GeneralData
{
public:
DataTypeA( ) : GeneralData() {}
~DataTypeA() {}
std::string uniqueName() { return std::string("Da taTypeA"); }

};

#endif

-----8<-----
//datatypeB.h

#ifndef DATATYPEB_H
#define DATATYPEB_H

#include "generaldat a.h"
#include <string>

class DataTypeB : public GeneralData
{
public:
DataTypeB( ) : GeneralData() {}
~DataTypeB() {}
std::string uniqueName() { return std::string("Da taTypeB"); }

};

#endif

-----8<-----
//typeAmaker.cc

#include "datatypeA. h"
#include "generalmaker.h "

char nameA[] = "DataTypeA" ;
//template<> //If I uncomment this, g++ 3.4 compiles but runs incorrectly
const GeneralMakerTP< DataTypeA, nameA>
GeneralMakerTP< DataTypeA,nameA >::registerThis ;

-----8<-----
//typeBmaker.cc

#include "datatypeB. h"
#include "generalmaker.h "

char nameB[] = "DataTypeB" ;
//template<> //If I uncomment this, g++ 3.4 compiles but runs incorrectly
const GeneralMakerTP< DataTypeB, nameB>
GeneralMakerTP< DataTypeB,nameB >::registerThis ;
--
My Hotmail address is a spam magnet. If replying by email,
please use erik dot arner at cgb dot ki dot se

Jul 22 '05 #2
Sorry, you may ask but I want to use the static data in the base template.
You use functions (they may have to be virtual) to return that data, but in
the derived class you make it return the appropriate static data.
In a way the base class is dealing with data that the derived class is going
to set. Lovely OOP.
Cheers.

"Charlie" <du*********@ya hoo.com> wrote in message
news:nk******** *********@news-server.bigpond. net.au...
Maybe (and I dont claim to be a guru) templates are generated code and
static members cause ambiguity, because they need to be specifically
called and 'typed'.
I had same problem and once I found a way around it, all hell came loose
when I tried to import/export.
So I removed the static members from the template and I called them in the
derived classes of the template
for example
class MyDerivedFromTe mplate : public YourTemplate< SomeClass >
{
static int s_number_of_obj ects;
.....
};

hope this helps.

"Erik Arner" <er********@hot mail.com> wrote in message
news:pa******** *************** *****@hotmail.c om...

Hi, I really need some help here. After upgrading to g++ 3.4 I have run
into all sorts of troubles that I'm sure depends on my lack of proper
understanding of C++. I would now like to get it right once and for all,
if possible.

Most severe is the problem illustrated by the code below. It's based on
the "pluggable factory pattern" described in

http://www.adtmag.com/joop/crarticle.asp?ID=1520

It's a generic factory class using templates to ease the addition of new
types to the hierarchy.

The code below is a simplified version of the system we use. It compiles
and runs fine and dandy with g++ 3.3.3, whereas 3.4.2 gives the error
message "too few template-parameter-lists". If I uncomment the
commented lines below (//template <>) both versions compile the code but
neither run properly - no output is produced. It has something to
do with instantiation of static members in template classes, AFAIU.
Expected output from the program is

DataTypeA
DataTypeB

Could someone please help me understand what's going on here? I'd be very
grateful. Code and some output below.

Thanks,
Erik

Successful run with g++ 3.3.3:

bash$ g++ -c main.cc
bash$ g++ -c generalmaker.cc
bash$ g++ -c typeAmaker.cc
bash$ g++ -c typeBmaker.cc
bash$ g++ -o makertest main.o generalmaker.o typeAmaker.o typeBmaker.o
bash$ ./makertest
DataTypeA
DataTypeB
bash$

Code:

-----8<-----
//main.cc

#include <iostream>
#include "generalmaker.h "
#include <string>
#include <list>

using namespace std;

int main() {

list<string> typelist = GeneralMaker::l istRegistered() ;

for( list<string>::i terator it = typelist.begin( ); it != typelist.end();
++it ) {
cerr<<*it<<endl ;
}

return 0;
}

-----8<-----
//generalmaker.h

#ifndef GENERALMAKER_H
#define GENERALMAKER_H

#include <map>
#include <string>
#include <list>

class GeneralData;

class GeneralMaker
{
public:
virtual ~GeneralMaker() {}
static GeneralData * newData( const std::string& );
static std::list<std:: string> listRegistered( );
protected:
GeneralMaker( ) {}
virtual GeneralData* makeData() = 0;
typedef std::map< std::string , GeneralMaker * > MakerMap;
static MakerMap & registry();

};

template <class Data, const char * str_>
class GeneralMakerTP : public GeneralMaker
{
protected:
GeneralMakerTP( ) : GeneralMaker( )
{
Data d;
std::string str = d.uniqueName();
GeneralMaker::r egistry().inser t( make_pair( str, this ) );
}
GeneralData* makeData()
{
return new Data();
}
static const GeneralMakerTP< Data, str_> registerThis;
};

#endif

-----8<-----
//generalmaker.cc

#include "generalmaker.h "
#include "generaldat a.h"

using namespace std;

list<string> GeneralMaker::l istRegistered()
{
list<string> list;

for ( MakerMap::const _iterator it = registry().begi n(); it !=
registry().end( ); ++it )
{
list.push_back( it->first );
}
return list;
}

GeneralMaker::M akerMap & GeneralMaker::r egistry()
{
/* We use this because static instances of sub classes of GeneralMaker
make use of this map. The idea comes from c++ faq lite
[10.12] How do I prevent the "static initialization order fiasco"?
*/

static GeneralMaker::M akerMap reg;
return reg;
}

GeneralData* GeneralMaker::n ewData( const std::string& generalDataType )
{
GeneralMaker* maker =
(*registry().fi nd( generalDataType )).second;
return maker ? maker->makeData() : NULL;
}

-----8<-----
//generaldata.h

#ifndef GENERALDATA_H
#define GENERALDATA_H

#include <string>
#include "generalmaker.h "
#include "generaldat a.h"
class GeneralData
{
public:
GeneralData() {}
virtual ~GeneralData(){ }

virtual std::string uniqueName() = 0;

};

#endif

-----8<-----
//datatypeA.h

#ifndef DATATYPEA_H
#define DATATYPEA_H

#include "generaldat a.h"
#include <string>

class DataTypeA : public GeneralData
{
public:
DataTypeA( ) : GeneralData() {}
~DataTypeA() {}
std::string uniqueName() { return std::string("Da taTypeA"); }

};

#endif

-----8<-----
//datatypeB.h

#ifndef DATATYPEB_H
#define DATATYPEB_H

#include "generaldat a.h"
#include <string>

class DataTypeB : public GeneralData
{
public:
DataTypeB( ) : GeneralData() {}
~DataTypeB() {}
std::string uniqueName() { return std::string("Da taTypeB"); }

};

#endif

-----8<-----
//typeAmaker.cc

#include "datatypeA. h"
#include "generalmaker.h "

char nameA[] = "DataTypeA" ;
//template<> //If I uncomment this, g++ 3.4 compiles but runs incorrectly
const GeneralMakerTP< DataTypeA, nameA>
GeneralMakerTP< DataTypeA,nameA >::registerThis ;

-----8<-----
//typeBmaker.cc

#include "datatypeB. h"
#include "generalmaker.h "

char nameB[] = "DataTypeB" ;
//template<> //If I uncomment this, g++ 3.4 compiles but runs incorrectly
const GeneralMakerTP< DataTypeB, nameB>
GeneralMakerTP< DataTypeB,nameB >::registerThis ;
--
My Hotmail address is a spam magnet. If replying by email,
please use erik dot arner at cgb dot ki dot se


Jul 22 '05 #3
On Mon, 22 Nov 2004 15:35:11 +0100, Erik Arner wrote:

It has something to
do with instantiation of static members in template classes, AFAIU.


OK, so I'm getting closer to the problem now. The problem is definitely
that the following lines in typeAmaker.cc (and correspondingly in
typeBmaker.cc) aren't parsed the way I expect them to:

char nameA[] = "DataTypeA" ;
template<>
const GeneralMakerTP< DataTypeA, nameA> GeneralMakerTP< DataTypeA,nameA >::registerThis ;

It seems that the compiler does not interpret this as an instantiation of
a static variable. I have no clue as to what the compiler makes of the
above statement. Is it ill-formed?

If I add empty parenthesis after registerThis (= a call to the default
constructor, right?) the compiler complains that there's no member
function of that name declared.

If I add a dummy constructor that takes an int to the GeneralMakerTP class
and call it instead, the program works correctly after this modified
statement:

char nameA[] = "DataTypeA" ;
template<>
const GeneralMakerTP< DataTypeA, nameA> GeneralMakerTP< DataTypeA,nameA >::registerThis (0);

This finally makes the compiler understand that I'm initalizing the
static member. I really want to avoid this kind of ugly hackery. Help much
appreciated. Any ideas?

Thanks,
Erik

Jul 22 '05 #4

OK, I think my problem boils down to the following. How do I initialize
A::a using the default constructor in the code below?

Thanks,
Erik

Code:

#include <iostream>

using namespace std;

template <class T>
class A
{
public:
A() { cerr<<"A() called"<<endl; }
A(int) { cerr<<"A(int) called"<<endl; }

private:
static A a;
};

// template<> A<int> A<int>::a();
/*
g++ 3.4.2: error: no member function `a' declared in `A<int>'
g++ 3.3.3: error: no member function `a' declared in `A<int>'
*/

// A<int> A<int>::a;
/*
g++ 3.4.2: error: too few template-parameter-lists
g++ 3.3.3: Compiles, output: A() called
*/

// template<> A<int> A<int>::a;
/*
g++ 3.4.2: Compiles, but no output
g++ 3.3.3: Compiles, but no output
*/

template<> A<int> A<int>::a(0);
/*
g++ 3.4.2: Compiles, output: A(int) called
g++ 3.3.3: Compiles, output: A(int) called
*/

int main()
{
return 0;
}
--
My Hotmail address is a spam magnet. If replying by email,
please use erik dot arner at cgb dot ki dot se

Jul 22 '05 #5
Erik Arner wrote in news:pa******** *************** *****@hotmail.c om in
comp.lang.c++:
OK, I think my problem boils down to the following. How do I initialize
A::a using the default constructor in the code below?

Thanks,
Erik

Code:

#include <iostream>

using namespace std;

template <class T>
class A
{
public:
A() { cerr<<"A() called"<<endl; }
A(int) { cerr<<"A(int) called"<<endl; }

private:
static A a;
};


Generic version:

template < typename T >
A< T > A< T >::a;

AFAICT you can't specialize a individual static member as
the syntax is needed for when the whole class is specialized:

template <> class A< int >
{
static A< double > a;
}

template <>
A< double > A< int >::a;

However no compiler I tried gave a sensible diagnostic when an
explicit specialization was provided *without* explicitly
specializing A< int >.

The best was Borland CBuilderX (EDG) that found A< int >::a was
an unresolved external for some reason. The others presumably
just ignored it.

You can however explicity (*) instantiate a specific static
member in a TU:

template A< int > A< int >::a;

HTH.

*) Can't remember the terminoligy for this, as I've never
needed to do it, "explicitly " is just a guess.

Rob.
--
http://www.victim-prime.dsl.pipex.com/
Jul 22 '05 #6
On 22 Nov 2004 19:53:10 GMT, Rob Williscroft <rt*@freenet.co .uk>
wrote:
Erik Arner wrote in news:pa******** *************** *****@hotmail.c om in
comp.lang.c+ +:
OK, I think my problem boils down to the following. How do I initialize
A::a using the default constructor in the code below?

Thanks,
Erik

Code:

#include <iostream>

using namespace std;

template <class T>
class A
{
public:
A() { cerr<<"A() called"<<endl; }
A(int) { cerr<<"A(int) called"<<endl; }

private:
static A a;
};


Generic version:

template < typename T >
A< T > A< T >::a;

AFAICT you can't specialize a individual static member as
the syntax is needed for when the whole class is specialized:

template <> class A< int >
{
static A< double > a;
}

template <>
A< double > A< int >::a;


That's incorrect - if the whole class is specialized, you shouldn't
use the template<> bit. That should be:

A<double> A<int>::a;

Here's a full example:

template <class T>
struct A
{
static A a;
};

//general definition
template <class T>
A<T> A<T>::a;

//specialization of a for double, with template<>
template<>
A<double> A<double>::a;

//whole class specialization for float, with template<>
template <>
struct A<float>
{
static A<float> a;
};

//definition of A<float>::a, no template<>
A<float> A<float>::a;

int main()
{
A<float>::a, A<double>::a, A<char>::a; //check defined
}

See 14.7.3/5.

Tom
Jul 22 '05 #7
Tom Widmer wrote in news:bl******** *************** *********@4ax.c om in
comp.lang.c++:

That's incorrect - if the whole class is specialized, you shouldn't
use the template<> bit. That should be:

A<double> A<int>::a;

See 14.7.3/5.


Thanks Tom, I've seen this before but managed to forget it.

However I modified your example:

#include <iostream>

template <class T>
struct A
{
A() { std::cout << "A< [" << typeid( T ).name() << "] >\n"; }
static A a;
};

//general definition
template <class T>
A<T> A<T>::a;

//specialization of a for double, with template<>
template<>
A<double> A<double>::a;

//whole class specialization for float, with template<>
template <>
struct A<float>
{
A() { std::cout << "A<float>\n "; }
static A<float> a;
};

//definition of A<float>::a, no template<>
A<float> A<float>::a;

template < typename T > void exists( T & ) {}

int main()
{
exists( A<float>::a );
exists( A<double>::a );
exists( A<char>::a );
}

The only compiler I have that compiled it was MSVC7.1 and it gave:

A<float>
A< [char] >

All the others (gcc/g++ 3.3,3.4,4.0 and BCCX 6.0 (EDG)) gave:

ccwlaaaa.o(.tex t+0xc5):test.cp p: undefined reference to `A<double>::a'

Or similar.

So I hope the OP can live with the generic version, as static member
specialization doesn't seem to be available yet :-(.

Rob.
--
http://www.victim-prime.dsl.pipex.com/
Jul 22 '05 #8

Thanks for the input! Comments below.

On Mon, 22 Nov 2004 19:53:10 +0000, Rob Williscroft wrote:
Erik Arner wrote in news:pa******** *************** *****@hotmail.c om in
comp.lang.c++:
OK, I think my problem boils down to the following. How do I initialize
A::a using the default constructor in the code below?
#include <iostream>

using namespace std;

template <class T>
class A
{
public:
A() { cerr<<"A() called"<<endl; }
A(int) { cerr<<"A(int) called"<<endl; }

private:
static A a;
};

Generic version:

template < typename T >
A< T > A< T >::a;


OK, this compiles but doesn't initialize the static member (of course).
[SNIP]

You can however explicity (*) instantiate a specific static
member in a TU:

template A< int > A< int >::a;


Wow. I've never seen this syntax before. If I use it alone (without the
generic version above), g++ 3.4.2 (and 3.3.3) says "error: explicit
instantiation of `A<int>::a' but no definition available". If I add the
generic version before it, it compiles and runs correctly. See below for
complete code that now works.

The same goes for my more complex example program earlier in the thread
(see separate post).

My only problem right now is that I don't quite understand what's going
on. Specifically:

* Why does everything work as I expect it to when I instantiate the static
member using the constructor that takes a parameter but not with the
default constructor? What's the fundamental difference?

* Does this solution (see below for code) follow the standard or shall I
expect it to break the next time I upgrade the compiler?

Again, many thanks for the help.

Regards,
Erik

Output (as expected and desired):

bash$ g++ -o test test.cc
bash$ ./test
A() called
bash$

Code:

//file: test.cc
#include <iostream>

using namespace std;

template <class T>
class A
{
public:
A() { cerr<<"A() called"<<endl; }

private:
static A a;
};
template <class T> A<T> A<T>::a;//Generic definition
template A<int> A<int>::a;//Specific definition

int main()
{
return 0;
}

--
My Hotmail address is a spam magnet. If replying by email,
please use erik dot arner at cgb dot ki dot se

Jul 22 '05 #9
On Mon, 22 Nov 2004 15:35:11 +0100, Erik Arner wrote:

Could someone please help me understand what's going on here? I'd be very
grateful.


As stated elsewhere in the thread, I think I have the problem under
control. The solution is to add a generic definition of the static member
in generalmaker.h, and remove the "<>" from "template <>" statement in the
..cc files (typeAmaker.cc and typeBmaker.cc).

My understanding of what's going on is still very limited. First and
foremost I wonder if the code below is stable and standards compliant, and
will behave the same the next time I go to a higher gcc version. Any input
would be appreciated.

Thanks,
Erik
Successful run with g++ 3.4.2:

bash$ g++ -c main.cc
bash$ g++ -c generalmaker.cc
bash$ g++ -c typeAmaker.cc
bash$ g++ -c typeBmaker.cc
bash$ g++ -o makertest main.o generalmaker.o typeAmaker.o typeBmaker.o
bash$ ./makertest
DataTypeA
DataTypeB
bash$

Code:

-----8<-----
//main.cc

#include <iostream>
#include "generalmaker.h "
#include <string>
#include <list>

using namespace std;

int main() {

list<string> typelist = GeneralMaker::l istRegistered() ;

for( list<string>::i terator it = typelist.begin( ); it != typelist.end(); ++it ) {
cerr<<*it<<endl ;
}

return 0;
}

-----8<-----
//generalmaker.h

#ifndef GENERALMAKER_H
#define GENERALMAKER_H

#include <map>
#include <string>
#include <list>

class GeneralData;

class GeneralMaker
{
public:
virtual ~GeneralMaker() {}
static GeneralData * newData( const std::string& );
static std::list<std:: string> listRegistered( );
protected:
GeneralMaker( ) {}
virtual GeneralData* makeData() = 0;
typedef std::map< std::string , GeneralMaker * > MakerMap;
static MakerMap & registry();

};

template <class Data, const char * str_>
class GeneralMakerTP : public GeneralMaker
{
protected:
GeneralMakerTP( ) : GeneralMaker( )
{
Data d;
std::string str = d.uniqueName();
GeneralMaker::r egistry().inser t( make_pair( str, this ) );
}
GeneralData* makeData()
{
return new Data();
}
static const GeneralMakerTP< Data, str_> registerThis;
};

// Following two lines added, generic definition of static member
template <class Data, const char * str_>
const GeneralMakerTP< Data, str_> GeneralMakerTP< Data, str_>::register This;

#endif

-----8<-----
//generalmaker.cc

#include "generalmaker.h "
#include "generaldat a.h"

using namespace std;

list<string> GeneralMaker::l istRegistered()
{
list<string> list;

for ( MakerMap::const _iterator it = registry().begi n(); it != registry().end( ); ++it )
{
list.push_back( it->first );
}
return list;
}

GeneralMaker::M akerMap & GeneralMaker::r egistry()
{
/* We use this because static instances of sub classes of GeneralMaker
make use of this map. The idea comes from c++ faq lite
[10.12] How do I prevent the "static initialization order fiasco"?
*/

static GeneralMaker::M akerMap reg;
return reg;
}

GeneralData* GeneralMaker::n ewData( const std::string& generalDataType )
{
GeneralMaker* maker =
(*registry().fi nd( generalDataType )).second;
return maker ? maker->makeData() : NULL;
}

-----8<-----
//generaldata.h

#ifndef GENERALDATA_H
#define GENERALDATA_H

#include <string>
#include "generalmaker.h "
#include "generaldat a.h"
class GeneralData
{
public:
GeneralData() {}
virtual ~GeneralData(){ }

virtual std::string uniqueName() = 0;

};

#endif

-----8<-----
//datatypeA.h

#ifndef DATATYPEA_H
#define DATATYPEA_H

#include "generaldat a.h"
#include <string>

class DataTypeA : public GeneralData
{
public:
DataTypeA( ) : GeneralData() {}
~DataTypeA() {}
std::string uniqueName() { return std::string("Da taTypeA"); }

};

#endif

-----8<-----
//datatypeB.h

#ifndef DATATYPEB_H
#define DATATYPEB_H

#include "generaldat a.h"
#include <string>

class DataTypeB : public GeneralData
{
public:
DataTypeB( ) : GeneralData() {}
~DataTypeB() {}
std::string uniqueName() { return std::string("Da taTypeB"); }

};

#endif

-----8<-----
//typeAmaker.cc

#include "datatypeA. h"
#include "generalmaker.h "

char nameA[] = "DataTypeA" ;
template
const GeneralMakerTP< DataTypeA, nameA> GeneralMakerTP< DataTypeA,nameA >::registerThis ;
//N.B., no <> after template

-----8<-----
//typeBmaker.cc

#include "datatypeB. h"
#include "generalmaker.h "

char nameB[] = "DataTypeB" ;
template
const GeneralMakerTP< DataTypeB, nameB> GeneralMakerTP< DataTypeB,nameB >::registerThis ;
//N.B., no <> after template
--
My Hotmail address is a spam magnet. If replying by email,
please use erik dot arner at cgb dot ki dot se

Jul 22 '05 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

7
12817
by: zhou | last post by:
Hi there, We have a compiler specific issue which requires us to force template instantiation. This works fine. The problem comes when I try using std:find() on vector. Since vector has no member function find() and I have to use std::find(). The linker fails on unsatisified symbols in find(). I think this is because find() is a template function and I have to force instantiation. However, I donot know the correct syntax of doing so....
16
2979
by: Eric | last post by:
I have a static class member variable as follows: struct A { static void Set (int i) { v = i; } static int& Get () { return v; } static int v; }; int A::v; // define A::v in the cpp file
7
12454
by: ank | last post by:
Hi, I was curious about how to define static data member of template class. Should I put the definition in a separate source file or in the same header file as its template class? And when this data will be initialized if it is used across many translation unit, assume that it has constructor and needs dynamic initialization? I have blindly searched for the answer but I still not thoroughly
4
1992
by: santosh | last post by:
Hello, I have a doubt about static variable. class B { private: static int x; public: static set(int y) {
12
2619
by: mlimber | last post by:
This is a repost (with slight modifications) from comp.lang.c++.moderated in an effort to get some response. I am using Loki's Factory as presented in _Modern C++ Design_ for message passing in an embedded environment with multiple processors. I created a policy for classes, which, I had hoped, would automatically register the class with the appropriate factory: // In some header file... #include <cassert>
5
2345
by: Hari | last post by:
Guys please help me to solve this strange problem what Iam getting as follows.. Trying to instantiate a global instance of a template class as follows :- when i build this code with debug and run this works fine. but if build in unicode release or release this does't work. IS THERE ANY PROBLEM OF INSTANTIATING TEMPLATE CLASSES
5
1655
by: tthunder | last post by:
Hi @all, I am looking for a good (compiler-independent) way to generate meaningful error messages, if specific (unintended) templates are instantiated. e.g. ------------
3
2960
by: erictham115 | last post by:
Error C2555 c:\C++ projects\stat1\stdmatrix_adapt.h(41) : error C2555: 'std_tools::Matrix_adapter<T>::at': overriding virtual function return type differs and is not covariant from 'ple::imtx_impl<T>::at' //in my program: the derived class template <class T> class Matrix_adapter : public ple::imtx_impl<T{ protected:
0
2924
by: greek_bill | last post by:
Hi, I have a template function for which I use SFINAE to restrict one of the parameters. Then I also have a partial specialization of this function.I would like to provide an explicit instantiation of the partially specialized version, but my compiler (VC8) complains because it fails the SFINAE version. I just realized as I was typing this that I'm using partial _function_ specialization. I'm sure I remember reading somewhere that
0
8921
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9284
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
0
9148
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
8151
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
6722
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
6022
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
4528
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
2
2683
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2165
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.