Archived

This topic is now archived and is closed to further replies.

FxMazter

Unresolved external in Member function

Recommended Posts

I am getting Unresolved External when inserting in a private static std::map from a public static function:
// IBase.h

class IBase {
public:
	virtual Init() =0;
	virtual Release() =0;
	virtual GetVersion() =0;

private:
	typedef IBase* (*CreateFn)();

	typedef std::map<const char*, CreateFn> InterfaceMap;

	static bool RegInterface(const char* ver, CreateFn createFn);
	static void RegImplementation(const char* ver);
	static void GetOwnInterface(const char* ver);
	static void GetOwnImplementation(const char* ver); 

	static InterfaceMap m_Interfaces;
};

// IBase.cpp

// I want to implement the RegInterface function

#include "IBase.h"

bool IBase::RegInterface(const char* ver, CreateFn createFn) {
	bool result = m_Interfaces.insert(
						InterfaceMap::value_type(ver, createFn)
						).second;
	return result;
}
I have tried to swap the std::map with a simple char* or int and tried to assign it a value in the RegInterface function... but it doesn't work... get an unresolved external there as well. Would appreciate any help, thx! (Got a new problem... please check last post) [edited by - FxMazter on January 17, 2004 5:09:59 PM]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Try this:


// IBase.cpp

// I want to implement the RegInterface function

#include "IBase.h"

IBase::InterfaceMap IBase::m_Interfaces;

bool IBase::RegInterface(const char* ver, CreateFn createFn) {
bool result = m_Interfaces.insert(
InterfaceMap::value_type(ver, createFn)
).second;
return result;
}



Share this post


Link to post
Share on other sites
Thx!

IBase::InterfaceMap IBase::m_Interfaces;

That was needed.

But could anyone explain why I would need the instantiation?

(Got a new problem... please check last post)

[edited by - FxMazter on January 17, 2004 5:10:17 PM]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
quote:
Original post by FxMazter
Thx!

IBase::InterfaceMap IBase::m_Interfaces;

That was needed.

But could anyone explain why I would need the instantiation?

From MSDN:

Static data members are not part of objects of a given class type; they are separate objects. As a result, the declaration of a static data member is not considered a definition. The data member is declared in class scope, but definition is performed at file scope. These static members have external linkage. The following example illustrates this:


// static_data_members.cpp

class BufferedOutput
{
public:
// Return number of bytes written by any object of this class.

short BytesWritten()
{
return bytecount;
}

// Reset the counter.

static void ResetCount()
{
bytecount = 0;
}

// Static member declaration.

static long bytecount;
};

// Define bytecount in file scope.

long BufferedOutput::bytecount;

int main()
{
}


In the preceding code, the member bytecount is declared in class BufferedOutput, but it must be defined outside the class declaration.



Share this post


Link to post
Share on other sites
I got stuck on another one now...
I have templated the IBase interface. Now this is because each possible interface will derive from this one. And The point with my architecture is that each type of Interface has the chared static map, not all of them...

Lets say I got a Renderer interface. Then I want to update that interface, so I derive a new RendererV2 from the Renderer. Now I register the RendererV2 interface. But this interface is not supposed to know anything about all the versions of the SceneGraph interface. (just so you get what I mean...)

Anyway, I templated the IBase and applied the same technique as above:


//IBase.h

template <class Interface>
class IBase {
public:
virtual ~IBase() {};
virtual Init() =0;
virtual Release() =0;
virtual GetVersion() =0;

typedef IBase<Interface>* (*CreateFn)();
typedef std::map<const char*, CreateFn> InterfaceMap;
static bool RegInterface(const char* ver, CreateFn createFn);
private:

static IBase<Interface>* QueryInterface(const char* ver);

static char* m_ver;
static InterfaceMap m_Interfaces;
};

//The implementations

template <class Interface>
IBase<Interface>::InterfaceMap IBase<Interface>::m_Interfaces;

template <class Interface>
bool IBase<Interface>::RegInterface(const char* ver, CreateFn createFn) {
bool result = m_Interfaces.insert(
InterfaceMap::value_type(ver, createFn)
).second;
return result;
}

template <class Interface>
IBase<Interface>* IBase<Interface>::QueryInterface(const char* ver) {
typedef InterfaceMap::const_iterator MI;
MI mapIter = m_Interfaces.find(ver);

if(mapIter != m_Interfaces.end()) {
//The second is a pointer to a CreateInterface function

return mapIter->second();
}

//Interface could not be retrieved... handle errors...

return NULL;
}



Now the compiler is complaining about this one:
template
IBase::InterfaceMap IBase::m_Interfaces;

"Syntax error: missing '';'' before IBase::m_Interfaces"

But I can assure you that I''m not missing any ";" anywhere near that assignment... unless it has something to do with this:


typedef std::map<const char*, CreateFn> InterfaceMap;


But that one seems ok as well... Sigh...

If anyone would guess what is wrong, that would be great. thx again.

Share this post


Link to post
Share on other sites
Templates allocate storage for statics slightly differently. In the header try:

template <class Interface>
typename IBase<Interface>::InterfaceMap IBase<Interface>::m_Interfaces;

Share this post


Link to post
Share on other sites
heh, thank you... I think It''s the second time I have this problem, not to mention that I didn''t remember it from the last time

And once again you are the one comming with salvation

thx!

Share this post


Link to post
Share on other sites
In case anyone will be interested, it seems that before using the static std::map, you will have to instatiate it for the templated type:



//this is not enough... the program craches when trying to

//use the m_Interfaces, std::map, for IBase<int>, IBase<char*>, or

//any other type

template <class Interface>
IBase<Interface>::InterfaceMap IBase<Interface>::m_Interfaces;

//Now the program won''t crash when you want to use

//the m_Interfaces, std::map, for IBase<int> class

//instantiation... same goes fo other types...

IBase<int>::InterfaceMap IBase<int>::m_Interfaces;


Am I right on this?

Share this post


Link to post
Share on other sites
then why do you need to have that first templated instantiation at all then?


//Why do you need this at all then?

template <class Interface>
IBase<Interface>::InterfaceMap IBase<Interface>::m_Interfaces;

//If you are gonna instantiate for every type you want to use?

IBase<int>::InterfaceMap IBase<int>::m_Interfaces;
IBase<MyClass>::InterfaceMap IBase<MyClass>::m_Interfaces;
//etc... ?



Don't get pissed... I'm just curious ?

[edited by - bilsa on January 17, 2004 8:36:54 PM]

[edited by - bilsa on January 17, 2004 8:38:24 PM]

Share this post


Link to post
Share on other sites
seems to me that one would have to instansiate each static member in templated classes for each instansation of the class. For example:

template
class A {
public:
static T m;
T n;
};

Now, if you wanted to use A and A, you would first need to do:

A::m = 10;
A::m = "Hello";

Of course, you''d use whatever values work for you.

Share this post


Link to post
Share on other sites