diff --git a/README.md b/README.md index fa2bce5..93dcf3b 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,18 @@ There is no way to disambiguate positional arguments from the value following a boolean, so we have chosen that they will be positional arguments, and therefore, `-o false` does not work. +## `std::vector` values + +Parsing of list of values in form of an `std::vector` is also supported, as long as `T` +can be parsed. To separate single values in a list the definition `CXXOPTS_VECTOR_DELIMITER` +is used, which is ',' by default. Ensure that you use no whitespaces between values because +those would be interpreted as the next command line option. Example for a command line option +that can be parsed as a `std::vector`: + +~~~ +--my_list=1,-2.1,3,4.5 +~~~ + ## Custom help The string after the program name on the first line of the help can be diff --git a/include/cxxopts.hpp b/include/cxxopts.hpp index a76bd84..a132daf 100644 --- a/include/cxxopts.hpp +++ b/include/cxxopts.hpp @@ -44,6 +44,10 @@ THE SOFTWARE. #define CXXOPTS_HAS_OPTIONAL #endif +#ifndef CXXOPTS_VECTOR_DELIMITER +#define CXXOPTS_VECTOR_DELIMITER ',' +#endif + #define CXXOPTS__VERSION_MAJOR 2 #define CXXOPTS__VERSION_MINOR 2 #define CXXOPTS__VERSION_PATCH 0 @@ -715,9 +719,13 @@ namespace cxxopts void parse_value(const std::string& text, std::vector& value) { - T v; - parse_value(text, v); - value.push_back(v); + std::stringstream in(text); + std::string token; + while(in.eof() == false && std::getline(in, token, CXXOPTS_VECTOR_DELIMITER)) { + T v; + parse_value(token, v); + value.emplace_back(std::move(v)); + } } #ifdef CXXOPTS_HAS_OPTIONAL diff --git a/src/example.cpp b/src/example.cpp index f245706..d3bbb0a 100644 --- a/src/example.cpp +++ b/src/example.cpp @@ -56,6 +56,7 @@ parse(int argc, char* argv[]) ("help", "Print help") ("int", "An integer", cxxopts::value(), "N") ("float", "A floating point number", cxxopts::value()) + ("vector", "A list of doubles", cxxopts::value>()) ("option_that_is_too_long_for_the_help", "A very long option") #ifdef CXXOPTS_USE_UNICODE ("unicode", u8"A help option with non-ascii: à. Here the size of the" @@ -130,6 +131,16 @@ parse(int argc, char* argv[]) std::cout << "float = " << result["float"].as() << std::endl; } + if (result.count("vector")) + { + std::cout << "vector = "; + const auto values = result["vector"].as>(); + for (const auto& v : values) { + std::cout << v << ", "; + } + std::cout << std::endl; + } + std::cout << "Arguments remain = " << argc << std::endl; return result; diff --git a/test/options.cpp b/test/options.cpp index e48e5f6..79715ee 100644 --- a/test/options.cpp +++ b/test/options.cpp @@ -512,6 +512,26 @@ TEST_CASE("Booleans", "[boolean]") { REQUIRE(result.count("others") == 1); } +TEST_CASE("std::vector", "[vector]") { + std::vector vector; + cxxopts::Options options("vector", " - tests vector"); + options.add_options() + ("vector", "an vector option", cxxopts::value>(vector)); + + Argv av({"vector", "--vector", "1,-2.1,3,4.5"}); + + char** argv = av.argv(); + auto argc = av.argc(); + + options.parse(argc, argv); + + REQUIRE(vector.size() == 4); + CHECK(vector[0] == 1); + CHECK(vector[1] == -2.1); + CHECK(vector[2] == 3); + CHECK(vector[3] == 4.5); +} + #ifdef CXXOPTS_HAS_OPTIONAL TEST_CASE("std::optional", "[optional]") { std::optional optional;