Commit 2aed1ce41b90bcc6134d90c2060480c877f1708b
Committed by
jarro2783
1 parent
da9210d4
Added parsing of general types. (#63)
Adds generic parsing of types using `operator>>`, in particular allows parsing of floats and doubles.
Showing
3 changed files
with
53 additions
and
0 deletions
include/cxxopts.hpp
| @@ -533,6 +533,16 @@ namespace cxxopts | @@ -533,6 +533,16 @@ namespace cxxopts | ||
| 533 | } | 533 | } |
| 534 | } | 534 | } |
| 535 | 535 | ||
| 536 | + template <typename T> | ||
| 537 | + void stringstream_parser(const std::string& text, T& value) | ||
| 538 | + { | ||
| 539 | + std::stringstream in(text); | ||
| 540 | + in >> value; | ||
| 541 | + if (!in) { | ||
| 542 | + throw argument_incorrect_type(text); | ||
| 543 | + } | ||
| 544 | + } | ||
| 545 | + | ||
| 536 | inline | 546 | inline |
| 537 | void | 547 | void |
| 538 | parse_value(const std::string& text, uint8_t& value) | 548 | parse_value(const std::string& text, uint8_t& value) |
| @@ -605,6 +615,15 @@ namespace cxxopts | @@ -605,6 +615,15 @@ namespace cxxopts | ||
| 605 | value = text; | 615 | value = text; |
| 606 | } | 616 | } |
| 607 | 617 | ||
| 618 | + // The fallback parser. It uses the stringstream parser to parse all types | ||
| 619 | + // that have not been overloaded explicitly. It has to be placed in the | ||
| 620 | + // source code before all other more specialized templates. | ||
| 621 | + template <typename T> | ||
| 622 | + void | ||
| 623 | + parse_value(const std::string& text, T& value) { | ||
| 624 | + stringstream_parser(text, value); | ||
| 625 | + } | ||
| 626 | + | ||
| 608 | template <typename T> | 627 | template <typename T> |
| 609 | void | 628 | void |
| 610 | parse_value(const std::string& text, std::vector<T>& value) | 629 | parse_value(const std::string& text, std::vector<T>& value) |
src/example.cpp
| @@ -49,6 +49,7 @@ int main(int argc, char* argv[]) | @@ -49,6 +49,7 @@ int main(int argc, char* argv[]) | ||
| 49 | "thisisareallylongwordthattakesupthewholelineandcannotbebrokenataspace") | 49 | "thisisareallylongwordthattakesupthewholelineandcannotbebrokenataspace") |
| 50 | ("help", "Print help") | 50 | ("help", "Print help") |
| 51 | ("int", "An integer", cxxopts::value<int>(), "N") | 51 | ("int", "An integer", cxxopts::value<int>(), "N") |
| 52 | + ("float", "A floating point number", cxxopts::value<float>()) | ||
| 52 | ("option_that_is_too_long_for_the_help", "A very long option") | 53 | ("option_that_is_too_long_for_the_help", "A very long option") |
| 53 | #ifdef CXXOPTS_USE_UNICODE | 54 | #ifdef CXXOPTS_USE_UNICODE |
| 54 | ("unicode", u8"A help option with non-ascii: à. Here the size of the" | 55 | ("unicode", u8"A help option with non-ascii: à. Here the size of the" |
| @@ -118,6 +119,11 @@ int main(int argc, char* argv[]) | @@ -118,6 +119,11 @@ int main(int argc, char* argv[]) | ||
| 118 | std::cout << "int = " << options["int"].as<int>() << std::endl; | 119 | std::cout << "int = " << options["int"].as<int>() << std::endl; |
| 119 | } | 120 | } |
| 120 | 121 | ||
| 122 | + if (options.count("float")) | ||
| 123 | + { | ||
| 124 | + std::cout << "float = " << options["float"].as<float>() << std::endl; | ||
| 125 | + } | ||
| 126 | + | ||
| 121 | std::cout << "Arguments remain = " << argc << std::endl; | 127 | std::cout << "Arguments remain = " << argc << std::endl; |
| 122 | 128 | ||
| 123 | } catch (const cxxopts::OptionException& e) | 129 | } catch (const cxxopts::OptionException& e) |
test/options.cpp
| @@ -336,3 +336,31 @@ TEST_CASE("Integer overflow", "[options]") | @@ -336,3 +336,31 @@ TEST_CASE("Integer overflow", "[options]") | ||
| 336 | options.parse_positional("positional"); | 336 | options.parse_positional("positional"); |
| 337 | CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::argument_incorrect_type); | 337 | CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::argument_incorrect_type); |
| 338 | } | 338 | } |
| 339 | + | ||
| 340 | +TEST_CASE("Floats", "[options]") | ||
| 341 | +{ | ||
| 342 | + cxxopts::Options options("parses_floats", "parses floats correctly"); | ||
| 343 | + options.add_options() | ||
| 344 | + ("double", "Double precision", cxxopts::value<double>()) | ||
| 345 | + ("positional", "Floats", cxxopts::value<std::vector<float>>()); | ||
| 346 | + | ||
| 347 | + Argv av({"floats", "--double", "0.5", "--", "4", "-4", "1.5e6", "-1.5e6"}); | ||
| 348 | + | ||
| 349 | + char** argv = av.argv(); | ||
| 350 | + auto argc = av.argc(); | ||
| 351 | + | ||
| 352 | + options.parse_positional("positional"); | ||
| 353 | + options.parse(argc, argv); | ||
| 354 | + | ||
| 355 | + REQUIRE(options.count("double") == 1); | ||
| 356 | + REQUIRE(options.count("positional") == 4); | ||
| 357 | + | ||
| 358 | + CHECK(options["double"].as<double>() == 0.5); | ||
| 359 | + | ||
| 360 | + auto& positional = options["positional"].as<std::vector<float>>(); | ||
| 361 | + CHECK(positional[0] == 4); | ||
| 362 | + CHECK(positional[1] == -4); | ||
| 363 | + CHECK(positional[2] == 1.5e6); | ||
| 364 | + CHECK(positional[3] == -1.5e6); | ||
| 365 | +} | ||
| 366 | + |