Template magic and pointers to member functions

Started by
2 comments, last by Deyja 17 years, 11 months ago
The basic idea of what I am trying to do is to create a template function that calls a member function.. well, it's hard to describe. As you'll see, the problem is that I can't pass the member function pointer as an argument.

template<typename R,typename T, typename C, R(C::*M)()>
R MethodThroughSmartPointer(T* thisp) { return (*thisp)->*M(); }

class foo
{
public:
	void bar() {}
};

typedef boost::shared_ptr<foo> foo_ptr;

void test()
{
	foo_ptr ptr = foo_ptr(new foo());
	MethodThroughSmartPointer<void,foo_ptr,foo,&foo::bar>(&ptr);
}

This, of course, does not compile. The problem is that M is not a pointer to a specific function, but a TYPE of function pointer. The only way this can work is if that SPECIFIC FUNCTION becomes part of the type of the template. This is especially frustrating because it works exactly as expected if the final argument is a normal function pointer and not a member function pointer. Just so you know; yes, is is absolutly impossible to pass the member function as an argument when calling the templated function. It has to be a template argument, not a function argument. The goal is to take the address of the generated function and call it with only the smartpointer as argument.
Advertisement
This works for me, MSVC++ 8exp. I think the nasty referencing can be simplified, but quick tries yielded little.
#include <boost/shared_ptr.hpp>#include <iostream>template<typename R,typename T, typename C, R(C::*M)()>R MethodThroughSmartPointer(T* thisp) { return ((&(*(*thisp)))->*M)(); }class foo{public:	void bar() {std::cout << "moo\n";}};typedef boost::shared_ptr<foo> foo_ptr;void main(){	foo_ptr ptr = foo_ptr(new foo());	MethodThroughSmartPointer<void,foo_ptr,foo,&foo::bar>(&ptr);}
Quote:Original post by Deyja
This, of course, does not compile. The problem is that M is not a pointer to a specific function, but a TYPE of function pointer.

Hmm? No... In your code, M is a pointer to a member function, not a type. You are, however, calling the function wrong. The calling code should be ((**thisp).*M)(); The avoidance of the ->* operator is because boost's smart pointer types do not have a bunch of template operator overloads for ->*, even though they really should, which could account for calls via member function pointers of any signature given a low number of parameters.

Also, you don't need T to be an explicit argument as you have it right now. Instead, just make it the last template parameter after R(C::*M)() and then have your compiler figure out the type from the call.

Quote:Original post by Deyja
Just so you know; yes, is is absolutly impossible to pass the member function as an argument when calling the templated function. It has to be a template argument, not a function argument. The goal is to take the address of the generated function and call it with only the smartpointer as argument.

Could you elaborate on that. To be honest, I really still don't see why you need the memberfunction pointer to be a template argument rather than a function argument. Making it an argument to the template instantiation would make things much easier and with your given example, would work fine.

Edit: Also, why are you passing a pointer to the smart pointer and why is it not a pointer to const? Your example doesn't require a pointer and you are also not doing anything to modify the smart pointer inside of your function. Really, you should just make the function take a reference to const T, where T is the smart poitner type, and work with that from within your definition.

Edit2: Actually, with the changes I just described in the previous edit, just creating overloads of ->* for the smart pointer would be the better bet as that is exactly what you want. Again, as I said earlier, boost really should have them already, but they're not too difficult for you to add.
The compiler can't figure it out from the call. Like I said; I'm taking a pointer to it. It's being bound to a scripting language - AngelScript - which uses inline assembly to call the function through the function pointer. I'm binding smart pointers to objects as types in angelscript. Unfortunatly, angelscript doesn't currently allow me to use operator-> so I have to write wrappers for all the member functions. The odd signature is required to interface properly with AngelScript. In any other situation, all your points would be absolutely correct. In fact, I can't actually see any reason to use a construct like this in any other situation.

But thanks. I'm going to go try your suggestions on how to fix the original problem.

This topic is closed to new replies.

Advertisement