Fix parsing of std::vector and add test, example and documentation (#182)

Improve parsing into std::vector so that a single argument can take a list.
This commit is contained in:
Christian Lang 2019-06-18 00:14:18 +02:00 committed by jarro2783
parent 1eca210edc
commit 7b14d5f60b
4 changed files with 54 additions and 3 deletions

View File

@ -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<T>` values
Parsing of list of values in form of an `std::vector<T>` 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<double>`:
~~~
--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

View File

@ -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<T>& 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

View File

@ -56,6 +56,7 @@ parse(int argc, char* argv[])
("help", "Print help")
("int", "An integer", cxxopts::value<int>(), "N")
("float", "A floating point number", cxxopts::value<float>())
("vector", "A list of doubles", cxxopts::value<std::vector<double>>())
("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<float>() << std::endl;
}
if (result.count("vector"))
{
std::cout << "vector = ";
const auto values = result["vector"].as<std::vector<double>>();
for (const auto& v : values) {
std::cout << v << ", ";
}
std::cout << std::endl;
}
std::cout << "Arguments remain = " << argc << std::endl;
return result;

View File

@ -512,6 +512,26 @@ TEST_CASE("Booleans", "[boolean]") {
REQUIRE(result.count("others") == 1);
}
TEST_CASE("std::vector", "[vector]") {
std::vector<double> vector;
cxxopts::Options options("vector", " - tests vector");
options.add_options()
("vector", "an vector option", cxxopts::value<std::vector<double>>(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<std::string> optional;