Я пишу несколько алгоритмов для построения случайных лесов, каждый лес будет
обучены на отдельных данных с отдельными функциями (каждое дерево будет использовать набор
функции с фиксированной сигнатурой, однако различные деревья будут обучаться с использованием
разные наборы функций, которые могут иметь разные сигнатуры), однако я
хотел бы просто написать код для построения случайных деревьев один раз, используя
шаблоны. В настоящее время у меня есть что-то вроде следующего:
класс T шаблона соответствует типу обучающих данных (например, патч изображения или
пиксель) шаблон класса V соответствует типу указателя функции
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
}
}
и я создаю объект так:
typedef double (*function_ptr)(TrainingDataPoint& data_point);
RandomTree<TrainingDataPoint, function_ptr> tree = ...
Проблема в том, что по причинам эффективности для одного из деревьев я
сборка, я хочу, чтобы набор функций (function_ptr) принимал не только
TrainingDataPoint (тип шаблона T), но кэш данных. Так что моя функция
указатель будет выглядеть так:
typedef double (*function_ptr)(TrainingDataPoint&,
unordered_map<string, cv::Mat>& preloaded_images);
Теперь проблема в том, что я не могу придумать, как сохранить класс RandomTree универсальным
но есть некоторые наборы функций (шаблон типа V), которые занимают больше, чем просто
тренировочный пункт (тип шаблона Т).
До сих пор я думал о:
Ни один из этих вариантов не кажется мне особенно привлекательным, надеюсь, кто-то может поделиться своим опытом и рассказать мне о лучшем способе?
Спасибо
Используйте функтор для функций, которым нужно состояние. Функтор в C ++ — это класс (или структура) с перегруженным оператором (), так что экземпляр функтора можно «вызвать как» функцию. Аргументами функтора в RandomTree должны быть именно те параметры, которые меняются и находятся под контролем RandomTree, остальные должны быть связаны снаружи. Пример функтора с дополнительным состоянием, которое оборачивает функцию:
template<typename Retval, typename Arg1, typename ExtraData>
struct BindExtraData
{
typedef Retval(*func_type)(Arg1, ExtraData);
BindExtraData( ExtraData const& d_, func_type func_ ):d(d_), func(func_) {};
ExtraData d;
func_type func;
Retval operator()( Arg1 a1 )
{
return func(a1, d);
}
};
но вы можете сделать лучше. Если это одноразовый, нет необходимости делать его шаблоном. bind2nd (ну, binder2nd) — это стандартная версия библиотеки выше, и она будет лучше написана.
Можете ли вы добавить еще один параметр в RandomTree, который принимает кэш. По умолчанию будет пустой кеш, если не указан. Например
template<typename T, typename V, typename CacheDataType = EmptyCache>
class RandomTree{ ... }
RandomTree<TrainingDataPoint, function_ptr, ProloadedImageCache>