Friday, December 25, 2009

Binding to member variables.

When we use boost::bind to bind to a member function, things are pretty easy. You're making a function object of a usually stand-alone or a member function. But when you bind to a member variable of a class, things get a little hazy. When binding to a member variable, usually, you get a member pointer to the type of the member variable. And if you are using this bind in the context of a STL algorithm, then you apply this data member pointer to the passed in argument. This makes absolutely no sense, but see the code below, and it will hopefully make more sense.


struct entry
{
typedef std::pair<int, bool> conn_type;
entry(int i, bool c) : conn_pair(i, c ) { }
// bool get_connecting() const { return connecting; }
conn_type conn_pair;
};

int main()
{
std::vector<entry> vec;
vec.push_back(entry(1, false));
vec.push_back(entry(2, false));
vec.push_back(entry(3, true));
vec.push_back(entry(4, false));


/// boost::bind(&entry::connecting, _1
/// Make a function object that willa lways return ***connecting***
/// member variable of the passed in object...
/// make a predicate that returns entry::connecting
/// create a member pointer. In this case of type
/// entry::*connectingPtr = &entry::connecting
/// returns _1.*connecting

if(std::find_if(vec.begin(), vec.end(), boost::bind(
&std::pair<int, bool>::second,
boost::bind(&entry::conn_pair, _1))) != vec.end())
{
std::cout << "Hey. Found one" << std::endl;
bool std::pair<int, bool>::*connectingPtr = &std::pair<int, bool>::second;
std::cout << std::boolalpha << vec.front().conn_pair.*connectingPtr << std::endl;
}

return 0;
}


And if you are one of those who think pointers to data members are not useful, think again. The benefit of them is that once you declare a pointer to point to a data member of a type, you can use on different instances of that type. This link explains it clearly: http://stackoverflow.com/questions/670734/c-pointer-to-class-data-member

int main()
{
int Car::*pSpeed = &Car::speed;
Car myCar;
Car yourCar;

//access different instances using the same pointer.
int mySpeed = myCar.*pSpeed;
int yourSpeed = yourCar.*pSpeed;

assert(mySpeed > yourSpeed); // ;-)

return 0;
}



You might argue that you can always add a getter function that returns to you the value you pointed to, and do without pointers headaches. Not so. Like I showed in the example above, sometimes you are using pre-existing classes, like std::pair, and have no better way to have succinct code, except to bind. Oh well.

0 comments: