Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

closure (delayed function call)


SourceForge.net Logo     CTTL on    
    SourceForge    
    Download    
    Latest    
    Documentation    
    Index    
    Library    
    News    
    CVS    
    Repository    
   Other    
   Links    

See also:
Limitation of higher-order functions is that nested functions work fine with free functions and function objects. However, a generalization of delayed function call is needed, to allow lambda expressions invoke member functions of objects.

Closures are abstractions of delayed function calls, encapsulating a function pointer (plus object reference, if member function is invoked.) In addition, closures store references to function arguments. (In this implementation, closures are limited to functions with only one or no arguments.) For example,

template< typename LambdaT >
void f( LambdaT lambda_ )
{
    lambda_.evaluate(); 
}

void g()
{
    int var = 0;
    std::vector< int > vect( 3 );
    // delayed "var = vect.size()":
    f(
        scalar( &var ) =
            *scalar( action(
                &vect,
                std::mem_fun( &std::vector< int >::size )
            )
    );
    assert( var == 3 );
}

Closures are somewhat tedious to write. The code must provide exact signature of the object and the function, including all template arguments for every template involved. To simplify notation for well known combinations of object types and members, for example, member functions of STL containers, the library provides a family of free functions put inside cttl::alias namespace. Assignment expression in sample above can be rewritten using alias::size() call:

template< typename LambdaT >
void f( LambdaT lambda_ )
{
    lambda_.evaluate(); 
}

void g()
{
    int var = 0;
    std::vector< int > vect( 3 );
    // delayed "var = vect.size()":
    f(
        scalar( &var ) = alias::size( scalar( &vect ) )
    );
    assert( var == 3 );
}

This change makes the above code a bit more readable.



As mentioned in scalar primitive documentation, scalars can be explicitly instantiated:

template< typename LambdaT >
void f( LambdaT lambda_ )
{
    lambda_.evaluate(); 
}

void g()
{
    // create scalar lambda containing an integer:
    lambda< int >::scalar var;

    std::vector< int > vect;
    // create reference scalar for vector:
    lambda< std::vector< int > >::scalar_reference refvect( &vect );
    f(
        // note extra parenthesis since f expects one argument!
        (
            alias::push_back( &refvect, 7 ) // vect.push_back( 7 )
            ,
            var = alias::size( refvect )    // var = vect.size()
        )
    );
    assert( vect.back() == 7 );
}

This sample reduces clutter of multiple cttl::scalar() helper calls that would otherwise instantiate every scalar primitive in-line.



As a general guideline for dealing with CTTL closures, one could use the following three steps:

Note that if function requires an argument, it should be specified by constant reference, or by mutable pointer. If argument is encapsulated by scalar primitive X, reference and pointer can be obtained as X.top() and &X.top(), respectively. For example,

template< typename LambdaT >
void f( LambdaT lambda_ )
{
    lambda< char >::scalar CH;
    ( CH = *lambda_ ).evaluate();         // (3)
    assert( CH.top() == 'A' );
}

void g()
{
    lambda< char >::scalar ch( 'a' );
    f(
        scalar(                           // (2)
            CTTL_STATIC_ACTION(           // (1)
                std::ptr_fun( &toupper ), // (1)(a)
                ch.top()                  // (1)(b)
            )
        )
    );
    assert( var == 3 );
}


closure helpers


The library provides a number of helper macros and functions for creation of CTTL closures. This section of documentation gives an overview of these facilities and sample code illustrations.

Notes:

CTTL_MEMBER_ACTION

(
    xobject,
    xaction,
    xargument
)
cttl::action(
    xobject,
    xaction,
    xargument
)

Returns closure for member function with one argument, where

xobject is a C++ object implementing desired member function. Constant objects are passed by reference; mutable objects - by address.

xaction is an instance of function pointer adaptor for unary member function.

xargument is a member function argument. Constant objects should be passed by reference; mutable objects - by address.

struct digit_parser {
    std::vector< std::string > vect_digit_names;
    lambda< char >::scalar sdigit;

    digit_parser()
        : vect_digit_names( 2 )
    {
        vect_digit_names[ 0 ] = "zero";
        vect_digit_names[ 1 ] = "one";
    }

    std::string get_digit_name( char digit_ ) const
    {
        assert( digit_ == 0 || digit_ == 1 );
        return vect_digit_names[ digit_ ];
    }

    template< typename UniverseT >
    size_t grammar( UniverseT& edge_ )
    {
        return (
            *(
                first( isdigit )
                &
                *(
                    // calculate digit that got parsed:
                    sdigit = scalar( edge_.first )[ 0 ] - '0',
                    // replace digit name:
                    scalar( &edge_ ) = *scalar( CTTL_MEMBER_ACTION(
                        *this,
                        std::mem_fun( &digit_parser::get_digit_name ),
                        sdigit.top()
                    ))
                )
            )
        ).match( edge_ );
    }

};

CTTL_MEMBER_ACTION_NOARG

(
    xobject,
    xaction
)
cttl::action(
    xobject,
    xaction
)

Returns closure for member function with no arguments, where

xobject is a C++ object implementing desired member function;

xaction is an instance of function pointer adaptor for unary member function.

#include "cttl/cttl.h"
#include "lambda/lambda.h"

using namespace cttl;

int main(int argc, char* argv[])
{
    int var = 0;
    std::vector< int > vect( 3 );
    
    (
        scalar( &var ) =
            *scalar( CTTL_MEMBER_ACTION_NOARG(
                vect,
                std::mem_fun( &std::vector< int >::size )
            ))
    ).evaluate();

    assert( var == 3 );

    return 0;
}

CTTL_STATIC_ACTION

(
    xaction,
    xargument
)
cttl::action(
    xaction,
    xargument
)

Returns closure for free function with one argument, where

xaction is a function pointer adaptor for global or static member unary function;

xargument function argument.

#include "cttl/cttl.h"
#include "lambda/lambda.h"

using namespace cttl;

// function with mutable argument
void fm( int& arg_ )
{
    ++arg_;
}

// function with constant argument
void fc( int arg_ )
{
    std::cout
        << arg_
        << std::endl
        ;
}

int main(int argc, char* argv[])
{
    // construct and initialize scalar:
    lambda< int >::scalar sint( 28 );

    (
        *scalar(
            CTTL_STATIC_ACTION(
                std::ptr_fun( &fm ),
                &sint.top()
            )
        )
    ).evaluate();

    assert( sint.top() == 29 );

    (
        *scalar(
            CTTL_STATIC_ACTION(
                std::ptr_fun( &fc ),
                sint.top()
            )
        )
    ).evaluate();

    return 0;
}

CTTL_STATIC_ACTION_NOARG

(
    xreseulttype,
    xaction
)
cttl::action<xreseulttype>(
    xaction
)

Returns closure for free function with no arguments. where

xaction is a function pointer;

xresulttype is a template parameter specifying function return type

#include "cttl/cttl.h"
#include "lambda/lambda.h"

void free_f()
{
}

using namespace cttl;

int main(int argc, char* argv[])
{
    (
        *scalar(
            CTTL_STATIC_ACTION_NOARG(
                void,
                &free_f
            )
        )
    ).evaluate();

    return 0;
}
   
#include "cttl/cttl.h"
#include "lambda/lambda.h"

int const& free_f()
{
    static const int value = 1;
    return value;
}

using namespace cttl;

int main(int argc, char* argv[])
{
    lambda< int >::scalar sint;
    (
        sint = *scalar(
            CTTL_STATIC_ACTION_NOARG(
                int const&,
                &free_f
            )
        ),
        CTTL_LAMBDA_ASSERT( sint == 1 )
    ).evaluate();

    return 0;
}

See also:



Copyright © 1997-2006 Igor Kholodov mailto:cttl@users.sourceforge.net.

Permission to copy, use, modify, sell and distribute this document is granted provided this copyright notice appears in all copies. This document is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose.


Generated on Thu Nov 2 17:48:53 2006 for CTTL Lambda Expression by  doxygen 1.3.9.1