Мне дали задание полировать интерфейс библиотеки кодеков. Мы используем C++ 17, и я могу использовать только стандартную библиотеку (т.е. без Boost). В настоящее время существует класс Decoder который выглядит примерно так:
class Decoder : public Codec {
public:
struct Result {
vector<uint8_t>::const_iterator new_buffer_begin;
optional<Metadata> metadata;
optional<Packet> packet;
};
Result decode(vector<uint8_t>::const_iterator buffer_begin,
vector<uint8_t>::const_iterator buffer_end);
private:
// irrelevant details
};
Вызывающий объект создает Decoder, а затем передает поток данных в декодер
-
Чтение фрагмента данных из файла (но в будущем возможны другие источники) и добавление его в
vector<uint8_t>. -
Вызов функции
decode, передача итераторов для их вектора. -
Если возвращенный
Resultnew_buffer_beginидентиченbuffer_beginкоторый был передан дляdecode, это означает, что в буфере недостаточно данных для декодирования чего-либо, и вызывающая сторона должна вернуться к шагу 1. В противном случае вызывающая сторона используетMetadataилиPacketобъект, который был декодирован, и возвращается к шагу 2, используяnew_buffer_beginдля следующего прохода.
Что мне не нравится в этом интерфейсе и что мне нужно улучшить:
-
Использование
vector<uint8_t>::const_iteratorкажется слишком конкретным. Есть ли более общий подход, который не заставляет абонента использоватьvector? Я думал только об использовании интерфейса в стиле C;uint8_t *и длина. Есть ли альтернатива C++, которая является довольно общей? -
Если данных было достаточно для декодирования чего-либо, значение будет иметь только
metadataилиpacket. Я думаю, чтоstd::variantили 2 обратных вызова (по одному для каждого типа) сделают этот код более самодокументированным. Я не уверен, что более идиоматично, хотя. Каковы плюсы и минусы каждого, и есть ли еще лучший подход?