Comments 3
Может быть это чистый и совершенный код, но как то сложновато в использовании. Чаще всего большая часть флагов - не выбор алгоритма, а настройка параметров типа имени входного файла или уровня оптимизации в компиляторе. Обычный подход, когда достаточно объявить глобальный объект, который "автоматически" инициализируется при парсинге командной строки и приводится к нужному типу, явно удобнее.
Мне кажется это решение несколько overengineering...
Я бы не рекомендовал создавать собственные коллекции без крайней необходимости. Это требует сил, времени, создает технический долг и требует отладки с покрытием тестами.
Если нужно ограничить функционал коллекции, я рекомендую приватно унаследовать стандартную коллекцию.
class Arguments : private std::span<const char*>
{
using PARENT = std::span<const char*>;
public:
inline Arguments(int n, const char** args) : PARENT(args, n) {}
inline auto begin() { return PARENT::begin(); }
inline auto end() { return PARENT::end(); }
inline auto size() { return PARENT::size(); }
};
Также я бы разделил ответственность вашего парсера на две. Сам парсер, на мой взгляд, должен заниматься непосредственно парсингом.
Группировать параметры по ключам и хранить значения.
Проверять корректность ввода. Ключ может быть флагом, или списком. Список может иметь допустимый набор параметров или маску. Формировать сообщение об ошибке ввода.
Автоматически формировать команду -h -help
Вторая часть ответственности, это настройка вашего приложения по параметрам. Чисто клиентский код программы.
Заметил давно уже такую закономерность - те, кто пытается писать с соблюдением SOLID и прочих принципов, пишут мерзкий код, который потом сложно читать/сопровождать/переписывать. В данном случае он еще и не безопасен (как минимум нужен override у виртуальных функций и не нужны virtual)
Чистый код: Аргументы командной строки