#pragma once #include #include #include namespace program::traits { template struct is_repeatable : std::false_type {}; template struct is_repeatable)>>>> : std::true_type {}; template constexpr bool const is_repeatable_v = is_repeatable::value; } namespace program { inline std::string join(std::string const & tok, std::vector const & data) { std::string accum = data.empty() ? "" : data.front(); for (size_t i = 1; i < data.size(); ++i) { accum += tok; accum += data[i]; } return accum; } template struct conversion_helper; /** * \brief Conversion method for positional arguments. Positional arguments are * always represented with a singular string. * \param name The name of the argument being parsed, for logging purposes * \param data A string containing the value to be processed. * \return An object of the given type */ template T convert(std::string const & name, std::string const & data) { return conversion_helper{}(data); } /** * \brief Conversion method for command-line options. Because some options are * repeatable, we need to pass in a vector of objects that might be used. * \param name The name of the option being parsed, for logging purposes * \param data A vector of arguments assigned to this option. * \invariant data.size() > 0 * \return An object of the given type * \throws ArgumentStructureError if the argument has been repeated but is * not a repeatable type. */ template T convert(std::string const & name, std::vector const & data) { conversion_helper helper; if constexpr (!traits::is_repeatable_v) { return helper(data); } else if (data.size() == 1) { return helper(data.front()); } throw ArgumentStructureError("Repeated option not allowed", name); } template struct conversion_helper< T, std::enable_if_t>> { T operator()(std::string const & str) const { return T(str); } }; template <> struct conversion_helper { int operator()(std::string const & str) const { return std::stoi(str); } }; template struct conversion_helper> : conversion_helper { std::vector operator()(std::vector const & data) const { std::vector rval; for (auto & str : data) { rval.emplace_back((*this)(str)); } return rval; } }; }