• Advertisement
Sign in to follow this  

Pointer to a template member function question.

This topic is 3317 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 don't know if the title might be confusing, but basically I wanted to know how to obtain the function pointer to a template function that is a member of a class. For example:
class A ...
class B : public A ...

class C
{
public:
    template < class T >
    A* function() {return new T();}
};
I tried a lot of different things, but couldn't really figure it out. I'm not entirely certain how to do it. It does work as just an independent function, which might not be too big of a problem. What I was doing was testing an idea of a factory object that could have the creation of other objects registered with it. Basically the interface was factory.assign<B>("class B"), and factory.create("B"). It worked really well, and I suppose I do not really NEED to have the object creation function be a member of the Factory class, but I thought it might be cleaner that way. Here is the code for the test, if anyone was interested:
#include <iostream>
#include <string>
#include <map>
#include <stdexcept>

using namespace std;

class Product
{
public:
};

class Pizza : public Product
{
public:
	Pizza() {cout << "New Pizza Created" << endl;}
};

class Sandwitch : public Product
{
public:
	Sandwitch() {cout << "New Sandwitch Created" << endl;}
};


template< class T >
Product* product_creation_function()
{
	return new T();
}

class Factory
{
public:
	typedef map< string, Product* (*)() > MyMap;

	template< class T >
	void assign(string name)
	{
		products[name] = &product_creation_function<T>;
	}

	Product* create(string name)
	{
		static MyMap::const_iterator iter;

		iter = products.find(name);

		if (iter != products.end())
		{
			return (iter->second)();
		}

		throw runtime_error("Factory was asked for non-existing key : " + name);

		return 0;
	}

private:
	MyMap products;
};


int main()
{
	Factory factory;

	factory.assign<Pizza>("pizza");
	factory.assign<Sandwitch>("sandwitch");

	factory.create("pizza");
	factory.create("sandwitch");
	factory.create("panda");

    return 0;
}


Share this post


Link to post
Share on other sites
Advertisement
You can't use function pointers with member functions, you need to use pointer to member functions and you need to explicitly instantiate the template (same goes with template free-functions) e.g.:


struct foo
{
template < typename Tp >
void bar() {}

template < typename Tp >
void bar() const {}

};
//....
void (foo::*mem1)() = &foo::bar<int>;
void (foo::*mem2)() const = &foo::bar<int>;

foo foobar;

(foobar.*mem1)();
(foobar.*mem2)();


Use a typedef to hide the ugliness:

typedef void (foo::*fugly)();
typedef void (foo::*fugly2)() const;

But you can make this more flexible, use boost::function and then you can use any callable entity (free-function, bound pointer to member function (check out boost::bind), of a functional object (user-defined type with the functional call operator overloaded).

Share this post


Link to post
Share on other sites
I almost think that there was a slight misunderstanding of what you thought I meant. I do want a pointer to a member function, and the code I'm using bares some similarity to the example you gave.

What I meant to say is that everything works just fine when the function is not a member of the class, but when the function is a member of the class I get a compilation error. I get these errors:
main.cpp|48|error: no matches converting function ‘creation_function’ to type ‘class Product* (*)()’|
main.cpp|40|error: candidates are: template<class T> Product* Factory::creation_function()|

because of this member function of Factory:
template< class T >
void assign(string name)
{
products[name] = &Factory::creation_function<T>; // Line 48
}

You said that I had to explicitly instantiate the template, but I think that would be done by the template used with the assign function.

Like I said, everything works fine when the function is moved out of the class, but I think it would be better if it were inside the Factory class. Then I could later say Factory<BaseClass> factory; and have factories that can produce any type of object instead of just ones derived from the Product class.

Share this post


Link to post
Share on other sites
Oh wait. I think I kind of almost figured it out. If I use
typedef map< string, Product* (Factory::*)() > MyMap;
with the pointer to (Factory::*) instead of just (*) I no longer get the same error.

Now I get the error:
main.cpp|59|error: must use ‘.*’ or ‘->*’ to call pointer-to-member function in 
‘iter.std::_Rb_tree_const_iterator<_Tp>::operator-> [with _Tp = std::pair<const
std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Product* (Factory::*)
()>]()->std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char>
>, Product* (Factory::*)()>::second (...)’|


However, when I try to use .* or ->* neither work.

Share this post


Link to post
Share on other sites
There we go!

Using the code:

return (this->*(iter->second))();

to call the function seems to work. The this pointer seemed to help and I was having a hard time figuring out the use a parenthesis.

Thanks for offering the help.

Share this post


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

  • Advertisement