flopbucket wrote:

After reading a bit about boost::lambda, I became curious how they

implemented it. I downloaded it and had a look, but the all the

headers and multiple templates make it a bit difficult to follow in a

short time (I only spent maybe 15 minutes).

Anyway, I decided to try some ideas out and came up with the following

basic example: (obviously this is very far from boost::lambda and is

special for streams, etc., but just trying to understand the basic

techniques they use).

(snip code)

Is this the *basic* idea of how they accomplish this?

One question I have that I couldnt figure out is, since the placeholder

needs to store a value, how can this be done without knowing before

hand? In my example, I delcared X to be Placeholder<std::stringsince

I am using a string in my simple test, but I know with boost::lambda, I

could put other types and _1 just works. I guess it is some template

magic that I can't figure out right now, but any hints / tips

appreciated.

Here is my attempt. This is the smallest example I could throw

together that (a) compiles, and (b) does something interesting.

namespace {

// This is basically the placeholder

class identity_functor {

public:

// Return type

template<typename arg1_type>

struct return_type {

typedef arg1_type type;

};

// Constructor (use default)

// Operator

template<typename arg1_type>

typename return_type<arg1_type>::type operator()(arg1_type s) {

return s;

}

};

// Constant functor

template<typename T>

class const_functor {

T _data;

public:

// Return type

template<typename arg1_type>

struct return_type {

typedef T type;

};

// Constructor (implicit)

const_functor(T __data)

: _data(__data) { }

// Operator

template<typename arg1_type>

typename return_type<arg1_type>::type operator()(arg1_type) {

return _data;

}

};

// Helper function (I shouldn't need this)

template <typename T>

const_functor<Tconstant(T t) {

return const_functor<T>(t);

}

// Sum functor

template <typename left_type,typename right_type>

class sum_functor {

left_type _left;

right_type _right;

public:

// Return type

template <typename arg1_type>

struct return_type {

typedef typename left_type::template

return_type<arg1_type>::type type;

};

// Constructor

sum_functor(left_type __left,right_type __right)

: _left(__left),

_right(__right) { }

// Operator

template<typename arg1_type>

typename return_type<arg1_type>::type operator()(arg1_type s) {

return _left(s)+_right(s);

}

};

// + operator

template<typename left_type,typename right_type>

sum_functor<left_type,right_typeoperator+(left_typ e

_left,right_type _right) {

return sum_functor<left_type,right_type>(_left,_right);

}

// Placeholders

identity_functor X;

}

int main() {

std::cout << (X+constant(1))(5) << std::endl;

return 0;

}

It appears to me that this is basically how boost::lambda works. The

trickiest part seems to be determining the return types. I just chose

to use the left-hand argument of addition to determine the type,

although it would be better to make a two-argument template which

picked the more precise type of the two. We just pass around arg1_type

as a template argument which is the type of the placeholder.

Several caveats: First, I had to put it into an unnamed namespace

because I use global templates to overload the operator. I wish I

could have a lambda_functor base class, but we can't have the templated

operator() be virtual (and we probably don't want to use inheritance

anyway, since it would slow things down). One downside to this is the

explicit constant() call which is required so that we operate on two

functor objects.

Second, there's a lot of issues with type traits. The reason I chose

operator+ as an example is because streams require references, while

these are all values. To get any more complicated, we'd need to have

to get into casting the template types into references and consts, and

I really don't understand that at all.

If anyone has further comments, I would really appreciate your input.

--

Steve Hicks