I've been given the task of polishing the interface of a codec library. We're using C++17, and I can only use the standard library (i.e. no Boost). Currently, there's a Decoder class that looks roughly like this:
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
};
The caller instantiates a Decoder, then feeds a stream of data to the decoder by
- Reading a chunk of data from a file (but there could be other sources in the future), and appending it to a - vector<uint8_t>.
- Calling the - decodefunction, passing the iterators for their vector.
- If the returned - Result's- new_buffer_beginis identical to the- buffer_beginthat was passed to- decode, that means there wasn't enough data in the buffer to decode anything, and the caller should go back to step 1. Otherwise, the caller consumes the- Metadataor- Packetobject that was decoded, and goes back to step 2, using- new_buffer_beginfor the next pass.
The things I dislike about this interface and need help improving:
- Using - vector<uint8_t>::const_iteratorseems overly specific. Is there a more generic approach that doesn't force the caller to use- vector? I was considering just using C-style interface; a- uint8_t *and a length. Is there a C++ alternative that's fairly generic?
- If there was enough data to decode something, only - metadataor- packetwill have a value. I think- std::variantor 2 callbacks (one for each type) would make this code more self-documenting. I'm not sure which is more idiomatic though. What are the pros and cons of each, and is there an even better approach?
 
     
     
    