Sign in to follow this  
NotAYakk

Member Functors

Recommended Posts

So, I've been playing around with C++ template magic. Being touched in the head, I got to thinking about aspect oriented programming, functors, and classes. What if one used member functors to allow each function in a class to have private state -- and more importantly, to allow metafunction programming? The simplest examples include "this function should only run once", or "this function should count the number of times it runs", or "this function should aquire a write lock on the class during it's execution". I'm not certain if the result is worthwhile. But as a concept it looks interesting to me. :) Here is a quick stab at it:
#include <stdio.h>
#include <windows.h>

template<typename parentptr, typename retval>
class MemberFunctor {
  protected:
    parentptr const self;
    virtual retval Work() = 0;
    MemberFunctor(parentptr self_):self(self_) {}
    
  public:
    retval operator()() {
      return Work();
    }   
};

template<typename parentptr, typename retval>
class RunOnceMemberFunctor:
		public MemberFunctor<parentptr, retval>
{
  private:
    bool has_run;
    retval cached;
  protected:
		RunOnceMemberFunctor(parentptr self_):MemberFunctor<parentptr, retval>(self_), has_run(false), cached() {}
  public:
		retval operator()() {
			if (!has_run) {
				has_run = true;
				cached = Work();
			}
			return cached;
		}
};
class test {
    int data;
  public:
    class Init:public RunOnceMemberFunctor<test*, bool> {
			bool Work() {
				#ifdef _DEBUG
				OutputDebugString("Initialize called!\n");
				#endif
				self->data = 'init';
				return true;
			};
		public:
			Init(test* self_):RunOnceMemberFunctor<test*, bool>(self_){};
    } Initialize; 
    
    class Clean:public RunOnceMemberFunctor<test*, bool> {
			bool Work() {
				#ifdef _DEBUG
				OutputDebugString("Clean called!\n");
				#endif
				bool retval = self->data == 'init';
				self->data = 'gone';
				return retval;
			}
		public:
			Clean(test* self_):RunOnceMemberFunctor<test*, bool>(self_){};
    } CleanUp;
    
    class Value:public MemberFunctor<test*, int> {
			int call_count;
			int Work() {
				++call_count;
				#ifdef _DEBUG
				char tmp[1024] = {0};
				sprintf(tmp, "Called %d times, value 0x%08x\n", call_count, self->data);
				OutputDebugString(tmp);
				#endif
				return self->data;
			};
		public:
			Value(test* self_):MemberFunctor<test*, int>(self_), call_count(0) {};
    } Read;
    
    class Reference:public MemberFunctor<test*, int&> {
			int call_count;
			int& Work() {
				++call_count;
				#ifdef _DEBUG
				char tmp[1024] = {0};
				sprintf(tmp, "Called %d times, value 0x%08x\n", call_count, self->data);
				OutputDebugString(tmp);
				#endif
				return self->data;
			};
		public:
			Reference(test* self_):MemberFunctor<test*, int&>(self_), call_count(0) {};
    } Write;
    
    test():Initialize(this), CleanUp(this), Read(this), Write(this), data(0) {}
};

bool tester() {
	test a;
	int v = a.Read();
	bool b = a.Initialize();
	v = a.Read();
	b = a.CleanUp();
	v = a.Read();
	b = a.Initialize();
	v = a.Read();
	b = a.CleanUp();
	v = a.Read();
	a.Write() = 0xBAADF00D;
	v = a.Read();
	return true;
};

bool meh = tester();
The above compiles (with warnings) under MSVC++2003, and I suspect it is standards-ok C++ code. I'm not certain that it saves much typing, but I did manage to move metafunction logic out of the implementation of the function and into the declaration of the functor.

Share this post


Link to post
Share on other sites
I think it can be pretty useful. I use something similar in my game: Objects have functors called Renderers that render the object. Currently, I render the terrain using a descedent of Renderer called DisplayListRenderer: The functor builds and displays the list the first time it gets executed, and the rest times it just displays it. The object has no idea how it's being rendered, all the relevant info(like the GL list id) is kept in the renderer.

Share this post


Link to post
Share on other sites
Now, making a virtual functor... That can be trickey.

Pseudo-code:

template<typename parent, typename signature, typename data>
struct VirtualFunctor: data {
private:
parent self;
typedef signature::retval(fun_type)(parent, data, signature::args);
fun_type* vfun;
signature::retval operator()(signature::args a) {
return vfun(self, *this, a);
}
VirtualFunctor(parent self_, fun_type* vfun):self(self_){}
void change_vfun(fun_type* vfun_){vfun=vfun_;}
};



not quite perfect. I suspect I want to store a void* to the data that the child virtual functor wants to access, and use template magic to call the right function.

Or maybe just use boost::function. Heh.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this