Friday, April 07, 2006

C++ : In a bind with function objects part II

So, this was my first attempt at the function object...


class doSomethingWithA :
public std:unary_function<A *, void>
{
void operator() (A *a)
{
std::string &name = a->GetName();
// Oh No! GetControlByName is a member of class B!
Control *control = GetControlByName(name);
if(control)
{
// so can’t use control here
bool value =
control->GetCurrentValue() > a->GetThreshold();
graphic.doSomething(value);
// graphic comes from class B too!
}
}
};


When I started to write this function object I was feeling pretty proud of myself, but as they say, pride comes before a fall and I immediately fell over on the second line of the overloaded operator() method (i.e. the bit that gives an instance of this class function syntax making it a function object with the signature we want). There’s no way to call the methods I need as they are part of class B, the owner of this container. Ok, so I guess I need to pass in a reference to an object of class B?


Unfortunately, the methods of class B which I needed were declared private, so short of changing the accessibilty (shudder) of these I was pretty stuck. It was at this point that I begun to think that perhaps this std::for_each algorithm wasn’t very useful? After all my first version of Update() using a for-loop worked with no head scratching at all. Then again, for-loops themselves used to be a mystery once upon a time (really?) so on I soldiered.


Right, what to do? I did a quick bit of online research thinking that perhaps I could pass a member function of class B as the third parameter of std::for_each and found this useful little function adaptor:


template<class Result, class Type>
std::mem_fun_t<Result, Type>
std::mem_fun(Result (Type::*pm)());


Sounds like a jovial name doesn’t it? “Mem Fun” implies it does something amusing with memory but it actually stands for “Member Function”, this function takes a pointer to a member function and returns a function object. Just the ticket I thought so I rushed in and started to implement the member function of class B that could use all the lovely private methods and data it needed to. A quick glance at the usage of std::mem_fun and I realised my mistake:


class T
{
public:
T(int v) : m_v(v) {}
void print() const
{
cout << m_v;
}
private:
int m_v;
};

vector<T> arr;
arr.push_back(1);
arr.push_back(2);
arr.push_back(3);

std::for_each(arr.begin(), arr.end(), std::mem_fun(&T::print));


Using std::mem_fun like this only works with a member function of the class you are using in std::for_each! This makes sense because in order to call a member function pointer you need an object as well and the only objects used in the std::for_each algorithm are the ones it gets from the first iterator parameter. Undeterred I had a sudden brainwave!


Find out what it was in part III

No comments: