473,758 Members | 5,909 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
18 5764
Erik Arner wrote in news:pa******** *************** ****@hotmail.co m in
comp.lang.c++:
Generic version:

template < typename T >
A< T > A< T >::a;
OK, this compiles but doesn't initialize the static member (of
course).


static members without a initializer are default-initialized, in
this case that means A< T >::A() is invoked.

But see Tom's correction to My post too.
[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?


Not sure what you mean here, but (see my reply to Tom) there aren't
AFAICT any compilers that get all of this static initialization /
specalization business right, so maybe its a compiler bug.

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


It's standard conforming (AFAICT) so it should work now and in the
future, it's also much simpler than trying to specialize a static
member so it should work everywhere now.

Rob.
--
http://www.victim-prime.dsl.pipex.com/
Jul 22 '05 #11
On 23 Nov 2004 11:17:17 GMT, Rob Williscroft <rt*@freenet.co .uk>
wrote:
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;


GCC bizarrely looks like treats that only as a declaration, and not a
definition. This fixed it for GCC:

template<>
A<double> A<double>::a = A<double>();

If I get como433 up and running again later, I'll give it a go and see
if it manages to compile the code.

Tom
Jul 22 '05 #12
On Tue, 23 Nov 2004 14:55:27 +0000, Rob Williscroft wrote:
Erik Arner wrote in news:pa******** *************** ****@hotmail.co m in
comp.lang.c++:
Generic version:

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


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


static members without a initializer are default-initialized, in
this case that means A< T >::A() is invoked.


But it doesn't produce any output until the next definition (see below) is
added, so I really don't understand what the statement actually does :-/
template A< int > A< int >::a;


This invokes the default constructor together with the generic version, it
seems. I still don't really grasp what's going on...

Thanks,
Erik

--
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 #13
On Tue, 23 Nov 2004 14:58:13 +0000, Tom Widmer wrote:
On 23 Nov 2004 11:17:17 GMT, Rob Williscroft <rt*@freenet.co .uk>
wrote:
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;


GCC bizarrely looks like treats that only as a declaration, and not a
definition. This fixed it for GCC:

template<>
A<double> A<double>::a = A<double>();


OK, so now the question becomes: which method is "better", i.e. which will
probably be more stable and not break with a more strict, future compiler?
Do both versions follow the standard? Both versions compile and work with
both g++ 3.3.3 and 3.4.2, and both versions compile without warnings with
the online version of Comeau 4.3.3 (www.comeaucomputing.com/tryitout).

Version A:

template <class T> A<T> A<T>::a;
template<> A<double> A<double>::a;

Version B:

template<> A<double> A<double>::a = A<double>();

Regards,
Erik

--
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 #14
Erik Arner wrote in news:pa******** *************** *****@hotmail.c om in
comp.lang.c++:
static members without a initializer are default-initialized, in
this case that means A< T >::A() is invoked.


But it doesn't produce any output until the next definition (see
below) is added, so I really don't understand what the statement
actually does :-/
template A< int > A< int >::a;


This invokes the default constructor together with the generic
version, it seems. I still don't really grasp what's going on...


Ok I think I get it now, because A a class template its members
don't get implicitly instantiated until you try to use them.

In the case of A< int >::a its necessary to reference it in some
way, say by accessing a member or passing a refrence or pointer
to a function.

The:

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

explicitly instantiates the member so it is no longer necessary
for the TU to reference it.

Rob.
--
http://www.victim-prime.dsl.pipex.com/
Jul 22 '05 #15
On Tue, 23 Nov 2004 15:24:34 +0000, Rob Williscroft wrote:

Ok I think I get it now, because A a class template its members
don't get implicitly instantiated until you try to use them.
Right.
In the case of A< int >::a its necessary to reference it in some
way, say by accessing a member or passing a refrence or pointer
to a function.

The:

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

explicitly instantiates the member so it is no longer necessary
for the TU to reference it.


But I still need the generic definition somewhere before this statement,
otherwise it won't compile.

/Erik

--
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 #16
Erik Arner wrote in news:pa******** *************** ****@hotmail.co m in
comp.lang.c++:

The:

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

explicitly instantiates the member so it is no longer necessary
for the TU to reference it.


But I still need the generic definition somewhere before this statement,
otherwise it won't compile.


Yes, the above is an instantiation not a declaration, so the
declaration is still needed.

Rob.
--
http://www.victim-prime.dsl.pipex.com/
Jul 22 '05 #17
Tom Widmer <to********@hot mail.com> wrote:
Rob Williscroft <rt*@freenet.co .uk> wrote:
Erik Arner wrote:
OK, I think my problem boils down to the following. How do I initialize
A::a using the default constructor in the code below?
template <class T>
struct A
{
static A 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;


(Bear with me, this is all new to me..)
I don't understand this line. It means that A<int> has a static
member whose type is A<double> ?
Supposing we then had:

A<float> A<int>::a;

and then in a function somewhere:
A<int> b;
foo(b.a)
how do we know whether it is foo(A<float>) or foo(A<double>)
that gets called?
Jul 22 '05 #18
Old Wolf wrote in news:84******** *************** ***@posting.goo gle.com
in comp.lang.c++:
Tom Widmer <to********@hot mail.com> wrote:
Rob Williscroft <rt*@freenet.co .uk> wrote:
template <class T>
struct A
{
static A 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;


(Bear with me, this is all new to me..)
I don't understand this line. It means that A<int> has a static
member whose type is A<double> ?
Supposing we then had:

A<float> A<int>::a;


But you can't the specalization A< int > that's been snipped is:

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

So A<int>::a has the declared type of A< double > trying to define
it as A< float > will be an error (illegal redeclaration or some
such).

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

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

Similar topics

7
12819
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
2983
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
12456
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
1993
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
2622
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
1660
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
2961
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
9298
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
1
9885
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
9737
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...
1
7286
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
6562
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
5172
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...
0
5329
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
3829
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
3
3399
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

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.