C++ Delegate Support

Programming, for all ages and all languages.
Post Reply
mehcode
Posts: 4
Joined: Sat Jun 05, 2010 3:07 pm

C++ Delegate Support

Post by mehcode »

Hello Everyone,

I was on #osdev earlier today when I was talking to someone... I can't remember. Anyway, we talked about C++ delegate support.

This way a single class that could bind to different function pointers and/or member function pointers (ala C# delegate). And perhaps an event class could be built on top allowing for intelligent C# events in C++ for user-land GUI programming (maybe?). Regardless I want - at least - fast delegates to be used as callbacks device drivers or other such areas of the OS.

There is a boost::function somewhere (which uses virtual memory mapping) but we're osdevers and we need something with as close to zero-overhead (tm) as possible.

DISCLAIMER: This code is a WIP and suggestions are more than welcome (in fact please give me suggestions to improve it :))

Code: Select all

template <typename TResult>
class Delegate
{
public:
	// [TODO] Some nice constructor so we can go Delegate(func) as an argument to a function
	//	  I suppose we could make the Bind functions static... but it's not very clean	

	template <TResult (*TMethod)()>
	void Bind()
	{
		m_Object = 0;
		m_Invoker = &Invoker<TMethod>;
	}

	template <typename TObject, TResult (TObject::*TMethod)()>
	void Bind(TObject *object)
	{
		m_Object = object;
		m_Invoker = &Invoker<TObject, TMethod>;
	}

	TResult Invoke()
	{
		return m_Invoker(m_Object);
	}

private:
	void *m_Object;
	TResult (*m_Invoker)(void*);

	template <TResult (*TMethod)()>
	static TResult Invoker(void*)
	{
		return (TMethod)();
	}
	
	template <typename TObject, TResult (TObject::*TMethod)()>
	static TResult Invoker(void *object)
	{
		TObject *p = static_cast<TObject*>(object);
		return (p->*TMethod)();
	}
	
};
To be used like this:

Code: Select all

class Foo
{
public:
     void Bar() { printf('B'); }
};

void Foo_Bar() { printf('A'); }

void Do()
{
       Delegate temp;
       temp.Bind<&Foo_Bar>();
       temp.Invoke();  // Prints 'A' to the screen

       Foo foo; // need an instance of the class

       temp.Bind<Foo, &Foo::Bar>(&foo);
       temp.Invoke(); // Prints 'B' to the screen            
}
(Compile and check the ASM output. Awesomely efficient and standard-compliant. :))

The code works as it is and compiles the latest version of G++. I know it only has a return type and no parameters but that's something I'm waiting to put in until I figure out an elegant constructor for these delegates.

As it is right now, I can' t figure out how to pass these efficiently as a function argument. Any suggestions?

[EDIT] Oops :oops: Typo on the Invoke function. Should be good now.
User avatar
Thomas
Member
Member
Posts: 281
Joined: Thu Jun 04, 2009 11:12 pm

Re: C++ Delegate Support

Post by Thomas »

Hi mehcode,
I am just posting some input that might be helpful to you . See : http://www.codeproject.com/KB/cpp/FastDelegate.aspx
--Thomas
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re: C++ Delegate Support

Post by Solar »

mehcode wrote:There is a boost::function somewhere (which uses virtual memory mapping) but we're osdevers and we need something with as close to zero-overhead (tm) as possible.
*cough*

A quick look at boost::function yielded this statement:
Q: How much overhead does a call through boost::function incur?

The cost of boost::function can be reasonably consistently measured at around 20ns +/- 10 ns on a modern >2GHz platform versus directly inlining the code.

However, the performance of your application may benefit from or be disadvantaged by boost::function depending on how your C++ optimiser optimises. Similar to a standard function pointer, differences of order of 10% have been noted to the benefit or disadvantage of using boost::function to call a function that contains a tight loop depending on your compilation circumstances.
I'm not sure how deep you looked into boost::function, but are you really sure your findings justify rolling your own vs. the usually very well-tested and supported Boost code?
Every good solution is obvious once you've found it.
User avatar
Owen
Member
Member
Posts: 1700
Joined: Fri Jun 13, 2008 3:21 pm
Location: Cambridge, United Kingdom
Contact:

Re: C++ Delegate Support

Post by Owen »

As much as I'm a fan of Boost - they produce some very good, very efficient and very well tested code (which is known to break compilers ;)) - I do have one issue with them.

They don't maintain ABI compatibility. If you use Boost version X in an interface, then all of your users must use version X too. If you upgrade to version Y, then you probably break all of your clients.
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re: C++ Delegate Support

Post by Solar »

Not really a fault of Boost. It's C++ "export" all over again...
Every good solution is obvious once you've found it.
User avatar
Owen
Member
Member
Posts: 1700
Joined: Fri Jun 13, 2008 3:21 pm
Location: Cambridge, United Kingdom
Contact:

Re: C++ Delegate Support

Post by Owen »

Standard Library implementers manage to have ABI compatibility. Its difficult, particularly for something heavily templated, yes, but its not impossible.
Post Reply