Jump to content
  • Advertisement
Sign in to follow this  
okonomiyaki

Storing templated function pointers

This topic is 4615 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'm working on a factory class, and basically when you register a new type it stores a templated function that creates an instance of that type. It's given me errors though. I'm wondering if you can do this? The code is rather short so I'll just post it instead of confusing you all with my awful explanation ability.
/* --------------------------------------------------------------
	File:			AXScene.h
	Description:	This file defines an class that manages a scene.

	Date:			December 19, 2005
	Author:			James
-------------------------------------------------------------- */

#if !defined(AXSCENE_INCLUDED)
#define AXSCENE_INCLUDED

class AXScene {
public:
	AXScene();
	virtual ~AXScene();

	template<class Type>
	void RegisterEntityType(string Name) {
		EntityRegistrar.insert(Name, &(EntityCreator<Type>));
	}

	shared_ptr<AXEntity> CreateEntity(string Type, string Name, string Parameters) {
		map<string, EntityCreatorPtr >::iterator Iter = EntityRegistrar.find(Type);
		if(Iter != EntityRegistrar.end()) return ((*Iter).second)(Name, Parameters);
		else return shared_ptr<AXEntity>();
	}

	shared_ptr<AXEntity> GetEntity(string Name) {
		map<string, shared_ptr<AXEntity> >::iterator Iter = EntityMap.find(Name);
		if(Iter != EntityMap.end()) return (*Iter).second;
		else return shared_ptr<AXEntity>();
	}

	AXSceneNode* GetRootSceneNode() {
		return &RootSceneNode;
	}

private:

	typedef shared_ptr<AXEntity> (*EntityCreatorPtr)(string, string);

	template<class Type>
	shared_ptr<AXEntity> EntityCreator(string Name, string Parameters) {
		shared_ptr<Type> Entity(new Type(Name, Parameters));
		EntityMap.insert(Name, Parameters);
		return Entity;
	}

	AXSceneNode RootSceneNode;
	map<string, shared_ptr<AXEntity> > EntityMap;
	map<string, EntityCreatorPtr> EntityRegistrar;
};


#endif

It's pretty obvious that the problem is I'm storing a type EntityCreatorPtr which has the same function declaration as EntityCreator without the template. And then I try to add something like "&(EntityCreator<Type>)". How can I store the generated function that creates an instance of a specific type? What kind of function declaration to I typedef as EntityCreatorPtr? I could solve this by using a templated class instead of a templated function, but I'm curious if you can even do this now.

Share this post


Link to post
Share on other sites
Advertisement
As far as I can tell you have two problems (and one point of really bad style). Problem one is that your call to std::map<>::insert() is incorrect in every place you use it. insert() takes a std::pair<key, value>, not two arguments. The second problem is that you're trying to assign a pointer to a member function to a regular function pointer. This is non-kosher. The bad point of style is that you seem to have a using namespace somewhere in your header file chain. Blech.

I got your code to compile with a few changes:

class AXScene {
public:
AXScene() {}
virtual ~AXScene() {}

template<class Type>
void RegisterEntityType(string Name) {
EntityRegistrar.insert( make_pair(Name, &AXScene::EntityCreator<Type> ) );
}

shared_ptr<AXEntity> CreateEntity(string Type, string Name, string Parameters) {
map<string, EntityCreatorPtr >::iterator Iter = EntityRegistrar.find(Type);
if(Iter != EntityRegistrar.end()) return (this->*(Iter->second))(Name, Parameters);
else return shared_ptr<AXEntity>();
}

shared_ptr<AXEntity> GetEntity(string Name) {
map<string, shared_ptr<AXEntity> >::iterator Iter = EntityMap.find(Name);
if(Iter != EntityMap.end()) return (*Iter).second;
else return shared_ptr<AXEntity>();
}

AXSceneNode* GetRootSceneNode() {
return &RootSceneNode;
}

private:

typedef shared_ptr<AXEntity> (AXScene::*EntityCreatorPtr)(string, string);

template<class Type>
shared_ptr<AXEntity> EntityCreator(string Name, string Parameters) {
shared_ptr<Type> Entity(new Type(Name, Parameters));
EntityMap.insert( make_pair(Name, Entity) );
return Entity;
}

AXSceneNode RootSceneNode;
map<string, shared_ptr<AXEntity> > EntityMap;
map<string, EntityCreatorPtr> EntityRegistrar;
};

Share this post


Link to post
Share on other sites
Ah, of course. (edit: said something stupid so I erased it.) Still working on function pointer syntax.

Also, I'm rather new to much of STL. Thanks for that correction. I used to use the [] operator but it's probably better to do an insert, so that's the first code I've written using the map's insert. It was something I meant to look up because I didn't think that's how it's done. Thought after adding "make_pair", I get an error; I'll have to look into it. In RegisterEntityType is says "could not deduce template argument for 'T1' from 'std::string'".

And as for your last point, should you really do a "using namespace ..." at the top of every file? for something like std, I use it in almost every file and it would require that. Yeah, it does it in a small file that defines some common types and macros.

Thanks!

Share this post


Link to post
Share on other sites
Quote:
Original post by okonomiyaki
Ah, of course. So I could either make the method static or make the changes you made? I suppose it's better to keep it a member function and make the syntax changes you made. Thanks.

Also, I'm rather new to much of STL. Thanks for that correction. I used to use the [] operator but it's probably better to do an insert, so that's the first code I've written using the map's insert. It was something I meant to look up because I didn't think that's how it's done. Thought after adding "make_pair", I get an error; I'll have to look into it. In RegisterEntityType is says "could not deduce template argument for 'T1' from 'std::string'".

And as for your last point, should you really do a "using namespace ..." at the top of every file? for something like std, I use it in almost every file and it would require that. Yeah, it does it in a small file that defines some common types and macros.

Thanks!


using namespace ...;

i reserve that for .cpp files that make heavy use of loads of namespace std;

otherwise i use the using directive
using std::vector;
using std::map;

in my header files i prefix all the standard library types and functions with std::

Share this post


Link to post
Share on other sites
You can use explicit template instantiation with the make_pair function or just manually create the pair object yourself. ex: make_pair<std::string, shared_ptr<AXEntity> >(Name, Entity). Or just use operator[] on the map. Registering a new type shouldn't be on your critical path so a little inefficiency shouldn't make that much of a difference.

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.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!