Мне дали задание полировать интерфейс библиотеки кодеков. Мы используем 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
, передача итераторов для их вектора. -
Если возвращенный
Result
new_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 обратных вызова (по одному для каждого типа) сделают этот код более самодокументированным. Я не уверен, что более идиоматично, хотя. Каковы плюсы и минусы каждого, и есть ли еще лучший подход?