c — Как использовать итераторы в чистой виртуальной функции шаблона класса?

#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*.