views:

127

answers:

1

Considering these two structs:

struct point {
    int x,y;
};

struct pinfo {
    struct point p;
    unsigned long flags;
};

And a function, that changes a point:

void p_map(struct point &p);

Is it possible to use boost (e.g. boost::bind or boost::lambda) to create a function equivalent with:

void pi_map(struct pinfo &pi) { p_map(pi.p); }

-edit: update for additional information:

The original intention for this function was to use it in for_each. For example given this function:

void p_map(struct point &p)
{
    p.x += 1;
    p.y += 1;
}

I could write:

void foreach(std::vector<struct pinfo> &pi_vec)
{
    for_each(pi_vec.begin(), pi_vec.end(), pi_map);
}

As it was suggested in an answer, it is possible to bound member variables with boost::lambda, and to create an alternative for_each version:

void foreach2(std::vector<struct pinfo> &pi_vec)
{
     boost::function<void (pinfo&)> pi_map2 = bind(&p_map, bind(&pinfo::p, _1));
     for_each(pi_vec.begin(), pi_vec.end(), pi_map2);
}

My issue with this approach, is that it gcc (v. 4.3.2) does not inline the pi_map and p_map functions for the foreach2 version.

The x86 code generated for the foreach1 function is:

0000000000400dd0 <foreach(std::vector<pinfo, std::allocator<pinfo> >&)>:
  400dd0:       48 8b 57 08         mov    0x8(%rdi),%rdx
  400dd4:       48 8b 07            mov    (%rdi),%rax
  400dd7:       48 39 c2            cmp    %rax,%rdx
  400dda:       74 14               je     400df0 <foreach(std::vector<pinfo, std::allocator<pinfo> >&)+0x20>
  400ddc:       0f 1f 40 00         nopl   0x0(%rax)
  400de0:       83 00 01            addl   $0x1,(%rax)
  400de3:       83 40 04 01         addl   $0x1,0x4(%rax)
  400de7:       48 83 c0 10         add    $0x10,%rax
  400deb:       48 39 c2            cmp    %rax,%rdx
  400dee:       75 f0               jne    400de0 <foreach(std::vector<pinfo, std::allocator<pinfo> >&)+0x10>
  400df0:        f3 c3              repz retq

Which implements the for_each, without calling any functions. On the other hand, the code generated for the foreach2 is more complicated, due to optimizations, and does not (seem to) inline the mapping functions.

However, this issue seems to be a philosophical, rather than a practical one with modern desktop processors, since (strangely enough) the performance on my machine is similar for both versions.

+6  A: 

You can do it with boost::lambda, member variables can be bound with bind the same way member functions are:

 #include <boost/function.hpp>
 #include <boost/lambda/bind.hpp>

 using namespace boost::lambda;

 boost::function<void (pinfo&)> pi_map = bind(&p_map, bind(&pinfo::p, _1));
sth
big +1. Very nice hidden gem.
Doug T.
Hi,Thanks for your reply!I've edited my original question to add some information about this approach.
ynimous