Я разрабатываю несколько алгоритмов обработки изображений на C ++. Чтобы сделать мой код более обобщенным и иметь возможность конфигурировать все без перекомпиляции всего проекта, у меня возникла идея разделить алгоритмы обработки на маленькие части («экстракторы»), сделать их объектами, унаследованными от одного интерфейса и настроить порядок их выполнения и параметры из файла XML, проанализированного фабричными методами. Но типы ввода и вывода этих базовых блоков обработки могут быть разными, поэтому я подумал об использовании boost :: any как обобщенного типа, поэтому каждая операция с изображением будет выглядеть так:
boost::any Process(const boost::any& feature);
Каждый объект должен хранить надлежащие типы ввода и вывода внутри и выполнять распаковку при каждом запуске. Это хорошая идея, чтобы использовать такую технику? Это как бы удовлетворяет мои потребности и будет очень естественным в Python, но в то же время выглядит как уродливый хак в C ++, который по своей природе статически типизирован, поэтому я сомневаюсь, что мне следует его использовать.
UPD: маленький пример, чтобы быть более понятным
// Base class for all processing
template <typename Input, typename Output>
class Processor {
public:
virtual ~Processor();
virtual Output Process(const Input& input) const = 0;
};
// Generalized type-erased processor
typedef Processor<boost::any, boost::any> TypeErasedProcessor;
// Boxing-unboxing wrapper
template <typename Input, typename Output>
class ProcessorWrapper: public TypeErasedProcessor {
public:
boost::any Process(const boost::any& boxed_input) const {
Input input = boost::any_cast<Input>(boxed_input);
Output output = processor_->Process(input);
boost::any boxed_output = output;
return boxed_output;
}
private:
std::shared_ptr<Processor<Input, Output>> processor_;
};
class SimpleImageProcessingChain: public TypeErasedProcessor {
public:
boost::any Process(const boost::any& input) const {
boost::any result = input;
for (const auto& processor: processors_) {
result = processor->Process(result);
}
return result;
}
private:
std::vector<std::shared_ptr<TypeErasedProcessor>> processors_;
};
В большинстве случаев удобочитаемость вашего кода важнее, чем возможность избежать перекомпиляции.
Если бы я работал с вашими алгоритмами, я бы определенно предпочел, чтобы они были статически типизированы.
В этом случае нет. Впрочем, ты бы этого не сделал
в Python тоже; ваша функция в Python не может принимать только
объект; он будет работать только с объектами, которые реализуют
конкретный протокол. Ваша функция не будет работать в Python, если
Вы передаете это float
или list
из string
; это будет только
работать, если вы передаете ему что-то, что ведет себя как изображение, и
имеет интерфейс изображения. Единственная разница между
Python и C ++ здесь, что в C ++, если объект реализует
протокол, он должен быть объявлен для этого, наследуя от
абстрактный базовый класс, который определяет интерфейс протокола.