Jump to content
  • Advertisement
Sign in to follow this  
simotix

Template Type Factory

This topic is 2663 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I am working on a factory that will have types added to them, however, if the class is not explicitly instiated in the .exe that is exectured (compile-time), then the type is not added to the factory. This is due to the fact that the static call is some how not being made. Does anyone have any suggestions on how to fix this? Below is five very small files that I am putting into a lib, then an .exe will call this lib. If there is any suggestions on how I can get this to work, or maybe a better design pattern, please let me know. Here is basically what I am looking for

1) A factory that can take in types
2) Auto registration to go in the classes .cpp file, any and all registration code should go in the class .cpp (for the example below, RandomClass.cpp) and no other files.

BaseClass.h

#pragma once

class BaseClass{ };


RandomClass.h

#pragma once

#include "BaseClass.h"

class RandomClass : public BaseClass
{
private:
static short ID;

public:
RandomClass();
virtual ~RandomClass();
};


RandomClass.cpp

#include "RandomClass.h"
#include "TemplatedFactory.h"

short RandomClass::ID = TemplatedFactory::GetInstance().AddType<RandomClass>("RandomClass");

RandomClass::RandomClass()
{

}

RandomClass::~RandomClass()
{

}


TemplateFactory.h

#pragma once

#include <map>
using std::map;

#include "BaseClass.h"

template<typename Type> BaseClass* createType() { return new Type; }

class TemplatedFactory
{
private:
typedef BaseClass* (*ComponentFactoryFuncPtr)();
typedef map<const char*, ComponentFactoryFuncPtr> map_type;

map_type m_Map;

public:
static TemplatedFactory &GetInstance();

template<typename Type>
short AddType(const char* typeName);
};

template<typename Type>
short TemplatedFactory::AddType(const char* typeName)
{
ComponentFactoryFuncPtr function = &createType<Type>;
m_Map.insert(std::make_pair(typeName, function));

return 0;
}


TemplateFactory.cpp

#include "TemplatedFactory.h"

TemplatedFactory &TemplatedFactory::GetInstance()
{
static TemplatedFactory instance;
return instance;
}

Share this post


Link to post
Share on other sites
Advertisement

[...]

This is due to the fact that the static call is some how not being made.

[...]

2) Auto registration to go in the classes .cpp file, any and all registration code should go in the class .cpp (for the example below, RandomClass.cpp) and no other files.

[...]


#include "RandomClass.h"
#include "TemplatedFactory.h"

short RandomClass::ID = TemplatedFactory::GetInstance().AddType<RandomClass>("RandomClass");



This kind of pre-registration stuff has popped up here quite a lot lately. It's inherently unreliable as even when it is made to work, one ends up relying on behaviour specific to the linker in question.

So, the portable solution is to avoid it completely I'm afraid. Instead, register all your classes at the start of the program.

For the full scoop as to why this doesn't work, you'll want to google for "dynamic initialization" and probably look in the C++ standard too. But the basic reason for the failure is that each ID variable isn't being used, so the linker excludes it and therefore excludes its initialization. "But the initialization has side-effects!", you say. Indeed but the linker doesn't know that. This page has a fuller explanation, which is GCC-centric, but applies just as well to the Visual C++ linker in many cases.

Share this post


Link to post
Share on other sites

[quote name='simotix' timestamp='1299306075' post='4781998']
[...]

This is due to the fact that the static call is some how not being made.

[...]

2) Auto registration to go in the classes .cpp file, any and all registration code should go in the class .cpp (for the example below, RandomClass.cpp) and no other files.

[...]


#include "RandomClass.h"
#include "TemplatedFactory.h"

short RandomClass::ID = TemplatedFactory::GetInstance().AddType<RandomClass>("RandomClass");



This kind of pre-registration stuff has popped up here quite a lot lately. It's inherently unreliable as even when it is made to work, one ends up relying on behaviour specific to the linker in question.

So, the portable solution is to avoid it completely I'm afraid. Instead, register all your classes at the start of the program.

For the full scoop as to why this doesn't work, you'll want to google for "dynamic initialization" and probably look in the C++ standard too. But the basic reason for the failure is that each ID variable isn't being used, so the linker excludes it and therefore excludes its initialization. "But the initialization has side-effects!", you say. Indeed but the linker doesn't know that. This page has a fuller explanation, which is GCC-centric, but applies just as well to the Visual C++ linker in many cases.
[/quote]

That is understandable. Is there perhaps a better design pattern?

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!