Click here to Skip to main content
11,478,642 members (63,915 online)
Click here to Skip to main content

Expression-based callbacks

, 12 Mar 2006 38.4K 17
Rate this:
Please Sign up or sign in to vote.
An easy way to provide expression-based callbacks in STL containers.

Introduction

In most cases where collections are used, the need to iterate over a collection, do a computation, and collect the results in a variable, arises often. This article shows an easy way to do this in C++, different from the most common approach, using containers together with expression templates. The article will use STL, but the technique can be applied to any container.

The common approach

The most usual approach to iteration over a collection is to use a for-loop. Writing for loops becomes tedious after a while, therefore many languages offer a 'for-each' statement that allows iteration over a collection. While C++ does not offer such a statement, it is very easy to implement it in various ways. The most common approach is to make a for-loop in a function that accepts a callback, like this:

template <class C> void forEach(C &c, 
            void (*callback)(C::value_type)) {
    for(C::iterator it = c.begin(); 
                    it != c.end(); ++it) {
        callback(*it);
    }
}

But this approach has some disadvantages; it interrupts the thought process of the programmer by making him/her think about where to place the callback, and also how to access the local data from inside the callback.

Expression templates

Expression templates come as a rescue: by using operator overloading, classes that represent an expression bound to local arguments can be used as a callback to a for-each loop. Before explaining how to code such classes, let's see an example of usage:

#include <list>
#include <iostream>
using namespace std;

int main()
{
    list<int> l;
    
    l.push_back(1);
    l.push_back(2);
    l.push_back(3);
    
    int i = 0;
    Expr< int > x;
    forEach(l, i, x += i);
    cout << x;
    getchar();
    return 0;
}

As you can see, it is much easier to sum a list of numbers using the above code!

How it works

Here is the important line of code; let's focus on it:

forEach(l, i, x += i);

C++ does not have lambda functions or closures, but it has operator overloading. So in the above code, x is an object that when operator += is applied to it, it does not actually add anything, but it creates a function object that encapsulates the variables x and i, and when invoked, it will perform the action.

The class Expr that x is an instance of is:

template <class T> class Expr {
public:
    Expr() : m_v(T()) {
    }

    ExprAddAssign<T> operator += (T &i) {
        return ExprAddAssign<T>(m_v, i);
    }
    
    operator T () const {
        return m_v;
    }
    
private:
    T m_v;    
};

We can see that it encapsulates a value of type T. We also see that operator += returns an instance of class ExprAddAssign, which is this class:

template <class T> class ExprAddAssign {
public:
    ExprAddAssign(T &lv, const T &rv) : 
                  m_lv(lv), m_rv(rv) {
    }
    
    void operator ()() const {
        m_lv += m_rv;
    }

private:
    T &m_lv;
    const T &m_rv;
};

The above class contains two bindings: one for the rvalue and one for the lvalue. The lvalue is assigned the value of rvalue. The code for the function 'forEach' becomes:

template <class C, class T, class F> 
         void forEach(const C &c, T &v, F &obj) {
    for(C::const_iterator it = c.begin(); 
                          it != c.end(); ++it) {
        v = *it;
        obj();
    }
}

Conclusion

A wide variety of expression templates can be programmed. Even constructs like if-then-else can be coded using a Smalltalk like syntax. Example:

forEach(l, (i > 2).ifTrue(x += i));

I actually accidentally came up with this solution, searching for a way to make lambda functions in C++. I realized that one does not need lambda functions, as long as lambda parameters can be declared as local variables.

I am surprised that the STL library does not contain such a set of classes. It would offer great power to C++...

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Achilleas Margaritis
Software Developer (Senior)
Greece Greece
No Biography provided

Comments and Discussions

 
GeneralBoost Pin
Stephen Hewitt12-Mar-06 21:41
memberStephen Hewitt12-Mar-06 21:41 
GeneralRe: Boost Pin
Stuart Dootson12-Mar-06 22:03
memberStuart Dootson12-Mar-06 22:03 
GeneralRe: Boost Pin
Stephen Hewitt12-Mar-06 22:44
memberStephen Hewitt12-Mar-06 22:44 
GeneralRe: Boost Pin
Achilleas Margaritis13-Mar-06 1:07
memberAchilleas Margaritis13-Mar-06 1:07 
GeneralRe: Boost Pin
Stephen Hewitt13-Mar-06 1:29
memberStephen Hewitt13-Mar-06 1:29 
GeneralRe: Boost Pin
Achilleas Margaritis13-Mar-06 5:25
memberAchilleas Margaritis13-Mar-06 5:25 
GeneralRe: Boost Pin
Stephen Hewitt13-Mar-06 12:31
memberStephen Hewitt13-Mar-06 12:31 
GeneralRe: Boost Pin
Achilleas Margaritis13-Mar-06 12:51
memberAchilleas Margaritis13-Mar-06 12:51 
GeneralRe: Boost Pin
Stephen Hewitt13-Mar-06 12:55
memberStephen Hewitt13-Mar-06 12:55 
GeneralRe: Boost Pin
Achilleas Margaritis14-Mar-06 1:09
memberAchilleas Margaritis14-Mar-06 1:09 
GeneralRe: Boost Pin
ikolev14-Mar-06 21:53
memberikolev14-Mar-06 21:53 
GeneralRe: Boost Pin
Stephen Hewitt14-Mar-06 23:26
memberStephen Hewitt14-Mar-06 23:26 
GeneralRe: Boost Pin
Jerry Jeremiah20-Jul-06 13:37
memberJerry Jeremiah20-Jul-06 13:37 
GeneralRe: Boost Pin
Stephen Hewitt20-Jul-06 15:13
memberStephen Hewitt20-Jul-06 15:13 
GeneralRe: Boost Pin
Jerry Jeremiah20-Jul-06 20:22
memberJerry Jeremiah20-Jul-06 20:22 
GeneralRe: Boost Pin
Stephen Hewitt20-Jul-06 20:52
memberStephen Hewitt20-Jul-06 20:52 
GeneralRe: Boost Pin
Jerry Jeremiah23-Aug-09 13:57
memberJerry Jeremiah23-Aug-09 13:57 
GeneralDLinq Pin
Keith Farmer12-Mar-06 16:18
memberKeith Farmer12-Mar-06 16:18 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.150520.1 | Last Updated 12 Mar 2006
Article Copyright 2006 by Achilleas Margaritis
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid