模板类中静态变量的实例化失败,为什么? [英] Instantiation of static variable in template class fails, why??

查看:115
本文介绍了模板类中静态变量的实例化失败,为什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



我真的需要一些帮助。在升级到g ++ 3.4之后,我已经运行了各种各样的麻烦,我肯定这取决于我对C ++缺乏正确的理解。我现在想要一劳永逸地做到这一点,
如果可能的话,还有b $ b。


最严重的问题是下面的代码所示。它是基于

的可插拔工厂模式

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

这是一个通用的工厂类,使用模板来轻松添加新的

类型到层次结构。


下面的代码是我们使用的系统的简化版本。它编译了

并使用g ++ 3.3.3运行良好和花花公子,而3.4.2给出了错误

消息模板参数列表太少。如果我取消注释下面的

注释行(// template<>),两个版本都会编译代码,但是

都没有正常运行 - 没有产生输出。在模板类AFAIU中实例化静态成员时,它可以实现


程序的预期输出是


DataTypeA

DataTypeB

感激不尽。代码和下面的一些输出。


谢谢,

Erik


使用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 $


代码:


----- 8< -----

//main.cc


#include< ; iostream>

#include" generalmaker.h"

#include< string>

#include< list>


使用命名空间std;


int main(){


list< string> typelist = GeneralMaker :: listRegistered();


for(list< string> :: iterator it = typelist.begin(); it!= typelist.end(); ++ it ){

cerr<< * it<< endl;

}


返回0;

}


----- 8< -----

//generalmaker.h


#ifndef GENERALMAKER_H

#define GENERALMAKER_H


#include< map>

#include< string>

#include< list>


类GeneralData;


类GeneralMaker

{

public:

virtual~GeneMMaker(){}

static GeneralData * newData(const std :: string&);

static std :: list< std :: string> listRegistered();

protected:

GeneralMaker(){}

虚拟GeneralData * makeData()= 0;

typedef std :: map< std :: string,GeneralMaker *> MakerMap;

静态MakerMap&注册表();


};


模板< class Data,const char * str_>

class GeneralMakerTP:public GeneralMaker

{

受保护:

GeneralMakerTP():GeneralMaker()

{

数据d;

std :: string str = d.uniqueName();

GeneralMaker :: registry()。insert(make_pair(str,this ));

}

GeneralData * makeData()

{

返回新数据();

}

static const GeneralMakerTP< Data,str_> registerThis;

};


#endif


----- 8< -----

//generalmaker.cc

#include" generalmaker.h"

#include" generaldata.h"


使用命名空间std;


list< string> GeneralMaker :: listRegistered()

{

list< string>列表;


for(MakerMap :: const_iterator it = registry()。begin(); it!= registry()。end(); ++ it)

{

list.push_back(it-> first);

}

返回列表;

}


GeneralMaker :: MakerMap& GeneralMaker :: registry()

{

/ *我们使用这个因为GeneralMaker子类的静态实例

使用这个地图。这个想法来自c ++ faq lite

[10.12]如何防止静态初始化命令惨败?

* /


静态GeneralMaker :: MakerMap reg;

返回reg;

}


GeneralData * GeneralMaker :: newData(const std :: string& generalDataType)

{

GeneralMaker * maker =

(* registry()。find(generalDataType))。second;

回报制造商? maker-> makeData():NULL;

}


----- 8< -----

//generangeata.h


#ifndef GENERALDATA_H

#define GENERALDATA_H


#include< string>

#include" generalmaker.h"

#include" generaldata.h"

class GeneralData

{

public:

GeneralData(){}

virtual~GeneralData(){}


virtual std :: string uniqueName()= 0;


};


#endif


----- 8< -----

//datatypeA.h

#ifndef DATATYPEA_H

#define DATATYPEA_H


#include" generaldata.h"

#include< string>


class DataTypeA:public GeneralData

{

public:

DataTypeA():GeneralData(){}

~DataTypeA (){}

std :: string uniqueName(){return std :: string(" DataTypeA"); }


};


#endif


----- 8< - ---

//datatypeB.h

#ifndef DATATYPEB_H

#define DATATYPEB_H


#include" generaldata.h"

#include< string>


class DataTypeB:public GeneralData

{

public:

DataTypeB():GeneralData(){}

~DataTypeB(){}

std :: string uniqueName(){return std :: string(" DataTypeB"); }


};


#endif


----- 8< - ---

//typeAmaker.cc

#include" datatypeA.h"

#include" generalmaker。 h"


char nameA [] =" DataTypeA";

// template<> //如果我取消注释,g ++ 3.4编译但运行不正确

const GeneralMakerTP< DataTypeA,nameA> GeneralMakerTP< DataTypeA,nameA> :: registerThis;


----- 8< -----

//typeBmaker.cc


#include" datatypeB.h"

#include" generalmaker.h"

char nameB [] = DataTypeB;

//模板<> //如果我取消注释,g ++ 3.4编译但运行不正确

const GeneralMakerTP< DataTypeB,nameB> GeneralMakerTP< DataTypeB,nameB> :: registerThis;

-

我的Hotmail地址是垃圾邮件磁铁。如果通过电子邮件回复,

请使用erik dot arner at cgb dot ki dot se


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::listRegistered();

for( list<string>::iterator 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::registry().insert( make_pair( str, this ) );
}
GeneralData* makeData()
{
return new Data();
}
static const GeneralMakerTP<Data, str_> registerThis;
};

#endif

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

#include "generalmaker.h"
#include "generaldata.h"

using namespace std;

list<string> GeneralMaker::listRegistered()
{
list<string> list;

for ( MakerMap::const_iterator it = registry().begin(); it != registry().end(); ++it )
{
list.push_back( it->first );
}
return list;
}

GeneralMaker::MakerMap & GeneralMaker::registry()
{
/* 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::MakerMap reg;
return reg;
}

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

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

#ifndef GENERALDATA_H
#define GENERALDATA_H

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

virtual std::string uniqueName() = 0;

};

#endif

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

#ifndef DATATYPEA_H
#define DATATYPEA_H

#include "generaldata.h"
#include <string>

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

};

#endif

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

#ifndef DATATYPEB_H
#define DATATYPEB_H

#include "generaldata.h"
#include <string>

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

};

#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

推荐答案

g ++ -c main.cc

bash
g++ -c main.cc
bash


g ++ -c generalmaker.cc

bash
g++ -c generalmaker.cc
bash


g ++ -c typeAmaker.cc

bash
g++ -c typeAmaker.cc
bash


这篇关于模板类中静态变量的实例化失败,为什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆