I am writing a few algorithms to build random forests, each forest will be
trained on separate data with separate functions (each tree will use a set of
functions with a fixed signature however different trees will be trained using
different sets of functions which could have a different signature), however I
would like to just write the code to build the random trees once, using
templates. I currently have something like the following:
template class T corresponds to the training data type (i.e. image patch, or
pixel) template class V corresponds to the function pointer type
template<class T, class V>
class RandomTree{
void build(RandomTreeNode<T>& current_node,
vector<V>& functions,
vector<T>& data) {
... some code that basically calls a function passing in data T
}
}
and I create the object like so:
typedef double (*function_ptr)(TrainingDataPoint& data_point);
RandomTree<TrainingDataPoint, function_ptr> tree = ...
The problem is that, for efficiency reasons, for one of the trees I’m
building, I want the set of functions (function_ptr’s) to take in not only the
TrainingDataPoint(template type T) but a cache of data. So that my function
pointer will look like:
typedef double (*function_ptr)(TrainingDataPoint&,
unordered_map<string, cv::Mat>& preloaded_images);
Now the problem is, I cant think of a way to keep the RandomTree class generic
but have some function sets (template type V) that take more than just the
training point (template type T).
So far I have thought of:
- Making the cache global so that the functions can access it
- adding a pointer to the cache to each training data point (but who is responsible for the clean up?)
- Adding a third template parameter to the RandomTree, but in this case if I am building a tree that doesn’t require this third parameter, what do I put there?
None of these options seem particularly appealing to me, hopefully someone can lend some experience and tell me of a better way?
Thanks
Use a functor for the functions that need state. A functor in C++ is a class (or struct) with an overloaded operator(), so that an instance of the functor can be “called like” a function. The arguments to the functor in the RandomTree should be exactly those parameters that vary and are under the control of the RandomTree, the rest should be bound outside. A sample functor with additional state that wraps a function:
but you can do better. If this is a one-off, there is no need to make it a template. bind2nd(well, binder2nd) is the standard library version of the above, and will be better written.