Thread: List of Functors

Threaded View

Previous Post Previous Post   Next Post Next Post
  1. #11
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    Okay, well here's a very basic example (believe it or not!). It should be bug-free, but you might need to do some testing, to be sure.

    Code:
    #include <memory>
    
    /*
    	Placeholder
    */
    struct DataType
    {	};
    
    /*
    	This is what all classes derive from. 
    	A function named 'process' must be defined, and can be inline.
    	Also known as 'The Curiously Recurring Template Idiom'.
    */
    template < typename Derived >
    struct function_base
    {
    	inline Derived& derived( void )
    	{
    		return *static_cast< Derived* >( this );
    	}
    
    	inline Derived const& derived( void ) const
    	{
    		return *static_cast< Derived const* >( this );
    	}
    	
    	inline void operator ( )( DataType& data )
    	{
    		derived( ).process( data );
    	}	
    };
    
    /*
    	This class provides the 'chaining' mechanism. Used internally only.
    */
    template < typename Lhs, typename Rhs >
    struct function_base_list : function_base< function_base_list< Lhs, Rhs > >
    {
    	function_base_list( function_base< Lhs > const& lhs, function_base< Rhs > const& rhs )
    	: lhs( lhs.derived( ) ), rhs( rhs.derived( ) )
    	{	}
    
    	inline void operator ( )( DataType& data )
    	{
    		lhs( data );
    		rhs( data );
    	}	
    	
    	Lhs
    		lhs;
    	Rhs
    		rhs;
    };
    
    /*
    	The 'chaining' generator.
    */
    template < typename Lhs, typename Rhs >
    function_base_list< Lhs, Rhs > operator + ( function_base< Lhs > const& lhs, function_base< Rhs > const& rhs )
    {
    	return function_base_list< Lhs, Rhs >( lhs, rhs );
    }
    
    /*
    	This class basically just simplifies things so that you:
    	1) don't have to write out a complex template declarations.
    	2) can assign a value to a function_base_list in the future, rather than immediately.
    	Since it's also derived from function_base_list, you can chain it to other lists, as well.
    	Ideally, it should use a smart pointer, but since this is just a simple example, 
    	I just went with an std::auto_ptr. The one nice thing about using that, though, 
    	is that it allows you to concatenate a greedy_function_base_holder to itself 
    	without creating a recursive situation.
    */
    struct greedy_function_base_holder : function_base< greedy_function_base_holder >
    {
    	struct base_dispatcher : function_base< base_dispatcher >
    	{
    		virtual void operator ( )( DataType& )
    		{	}
    	};
    	
    	template < typename Derived >
    	struct derived_dispatcher : base_dispatcher
    	{
    		derived_dispatcher( function_base< Derived > const& self )
    		: self( self.derived( ) )
    		{	}
    	
    		virtual void operator ( )( DataType& data )
    		{
    			self( data );
    		}
    		
    		Derived
    			self;
    	};
    
    	greedy_function_base_holder( void )
    	{
    		*this = base_dispatcher( );
    	}
    	
    	greedy_function_base_holder( greedy_function_base_holder const& rhs )
    	{
    		*this = rhs;
    	}
    
    	template < typename Derived >
    	greedy_function_base_holder( function_base< Derived > const& rhs )
    	{
    		*this = rhs;
    	}
    	
    	greedy_function_base_holder& operator = ( greedy_function_base_holder const& rhs )
    	{
    		greedy_function_base_holder&
    			sap = const_cast< greedy_function_base_holder& >( rhs );
    		ptr = sap.ptr;
    		sap = base_dispatcher( );
    		return *this;
    	}
    
    	template < typename Derived >
    	greedy_function_base_holder& operator += ( function_base< Derived > const& rhs )
    	{
    		return *this = *this + rhs;
    	}
    	
    	template < typename Derived >
    	greedy_function_base_holder& operator = ( function_base< Derived > const& rhs )
    	{
    		ptr = std::auto_ptr< base_dispatcher >( new derived_dispatcher< Derived >( rhs ) );
    		return *this;
    	}
    	
    	inline void operator ( )( DataType& data )
    	{
    		( *ptr.get( ) )( data );
    	}	
    	
    	std::auto_ptr< base_dispatcher >
    		ptr;
    };
    
    // Example:
    
    #include <iostream>
    
    using namespace 
    	std;
    
    struct test : function_base< test >
    {
    	test( int value = 0 )
    	: value( value )
    	{	}
    	
    /*
    	Parameter unused for test
    */	
    	inline void process( DataType& )
    	{
    		cout << value << endl;
    	}	
    
    	int
    		value;
    };
    
    int main( void )
    {
    	DataType
    		unused;
    	greedy_function_base_holder
    		gfbh1 = test( 1 ) + test( 2 ) + test( 3 ), 
    		gfbh2 = gfbh1 + test( 4 ) + test( 5 ) + test( 6 );
    	gfbh2 += test( 7 ) + test( 8 ) + test( 9 );	
    	gfbh2( unused );	
    	return 0;
    }
    EDIT: Oh and maybe I should make this clear: the greedy_function_base_holder is called 'greedy' because it will 'take' the underlying data from any greedy_function_base_holder's chained to it. So for instance, 'gfbh1' in the example above loses it's data after it is chained to 'gfbh2'. Like I said, a smart pointer would be a better approach for that class (just be careful with cyclic references!).
    Last edited by Sebastiani; 09-29-2009 at 01:50 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Link List math
    By t014y in forum C Programming
    Replies: 17
    Last Post: 02-20-2009, 06:55 PM
  2. instantiated from here: errors...
    By advocation in forum C++ Programming
    Replies: 5
    Last Post: 03-27-2005, 09:01 AM
  3. How can I traverse a huffman tree
    By carrja99 in forum C++ Programming
    Replies: 3
    Last Post: 04-28-2003, 05:46 PM
  4. List class
    By SilasP in forum C++ Programming
    Replies: 0
    Last Post: 02-10-2002, 05:20 PM
  5. singly linked list
    By clarinetster in forum C Programming
    Replies: 2
    Last Post: 08-26-2001, 10:21 PM