#c #templates #iterator #virtual
Вопрос:
Я хочу объявить класс интерфейса для процессора данных с методом «процесс», который принимает итераторы в качестве аргументов: «начало» и «конец» указывают на первый и (за) последний элемент данных типа T для обработки, «пункт назначения» указывает на позицию, в которую должны быть скопированы обработанные данные типа T.
Цель состоит в том, чтобы подклассировать этот интерфейс и позволить фабрике решить, какой из подклассов должен быть создан для обработки данных. Это не работает, если интерфейс не может быть определен аналогично следующему:
template<typename T>
class Data_processor
{
public:
virtual void process_data(It_In start, It_In end, It_out destination) = 0;
};
Есть идеи, как это можно сделать?
Комментарии:
1. Если вы хотите работать с «любым» итератором в виртуальном контексте, вам потребуется некоторое стирание типов. поскольку метода виртуального шаблона не существует. Например, что-то вроде:
void process_data(std::function<std::optional<T>()> generator, std::function<void(T)> onElementProcessed)
2. Почему класс является шаблоном? Этого не должно быть. И почему
process_data
функция не является шаблоном? Это необходимо, так как вы не знаете типов итераторов.3. Что вы подразумеваете под «Это не сработает, если…»? Кроме того, мне неясно, с какой проблемой вы столкнулись. Кроме того, ваш шаблон не используется
T
.4. И, похоже
std::transform
, вместо этого ваш код мог бы использоватьprocess_data
функцию, которая берет фактические данные и выполняет некоторую обработку, возвращая «новые» и обработанные данные. Или данные следует оставить неизмененными, простоprocess_data
для «обработки»требуется постоянная ссылка на какой-то неизвестный тип.5. Все зависит от требований, которые не описаны в этом вопросе. Это возможно, но в зависимости от деталей чем-то придется пожертвовать: не виртуальной функцией, ограничиться определенным типом контейнера (итератор), добавить некоторую абстракцию на итераторе (более медленный код).
Ответ №1:
Похоже, что код, который будет вызывать process_data
, может вместо этого вызывать std::transform
с Data_processor
помощью функции как неоперативная операция.
Т. е. вместо
template<typename T>
class Data_processor
{
public:
virtual void process_data(It_In start, It_In end, It_out destination) = 0;
};
Data_processor<int> * processor = factory.make_processor<int>(args...);
processor->process_data(source.begin(), source.end(), dest.begin());
Вы бы сделали
template<typename T>
class Data_processor
{
public:
virtual T operator()(T datum) = 0;
};
Data_processor<int> * processor = factory.make_processor<int>(args...);
std::transform(source.begin(), source.end(), dest.begin(), std::ref(*processor));
Однако , если нет других участников Data_processor
, вы могли бы использовать std::function<T(T)>
вместо этого.
std::function<int(int)> processor = factory.make_processor<int>(args...);
std::transform(source.begin(), source.end(), dest.begin(), processor);
Комментарии:
1. Спасибо за ваш ответ! К сожалению, обработанные данные не могут быть обработаны независимо, т. е. некоторые элементы должны быть сдвинуты/обменены, поэтому функция преобразования здесь не может быть использована. Мое текущее решение состоит в том, чтобы вместо этого использовать указатели T*.