From 2aed1ce41b90bcc6134d90c2060480c877f1708b Mon Sep 17 00:00:00 2001 From: Hannah Rittich Date: Wed, 16 Aug 2017 09:55:06 +0200 Subject: [PATCH] Added parsing of general types. (#63) Adds generic parsing of types using `operator>>`, in particular allows parsing of floats and doubles. --- include/cxxopts.hpp | 19 +++++++++++++++++++ src/example.cpp | 6 ++++++ test/options.cpp | 28 ++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+) diff --git a/include/cxxopts.hpp b/include/cxxopts.hpp index 72cf54e..0d54815 100644 --- a/include/cxxopts.hpp +++ b/include/cxxopts.hpp @@ -533,6 +533,16 @@ namespace cxxopts } } + template + void stringstream_parser(const std::string& text, T& value) + { + std::stringstream in(text); + in >> value; + if (!in) { + throw argument_incorrect_type(text); + } + } + inline void parse_value(const std::string& text, uint8_t& value) @@ -605,6 +615,15 @@ namespace cxxopts value = text; } + // The fallback parser. It uses the stringstream parser to parse all types + // that have not been overloaded explicitly. It has to be placed in the + // source code before all other more specialized templates. + template + void + parse_value(const std::string& text, T& value) { + stringstream_parser(text, value); + } + template void parse_value(const std::string& text, std::vector& value) diff --git a/src/example.cpp b/src/example.cpp index f9f50b2..44271b4 100644 --- a/src/example.cpp +++ b/src/example.cpp @@ -49,6 +49,7 @@ int main(int argc, char* argv[]) "thisisareallylongwordthattakesupthewholelineandcannotbebrokenataspace") ("help", "Print help") ("int", "An integer", cxxopts::value(), "N") + ("float", "A floating point number", 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" @@ -118,6 +119,11 @@ int main(int argc, char* argv[]) std::cout << "int = " << options["int"].as() << std::endl; } + if (options.count("float")) + { + std::cout << "float = " << options["float"].as() << std::endl; + } + std::cout << "Arguments remain = " << argc << std::endl; } catch (const cxxopts::OptionException& e) diff --git a/test/options.cpp b/test/options.cpp index 69cb964..1446929 100644 --- a/test/options.cpp +++ b/test/options.cpp @@ -336,3 +336,31 @@ TEST_CASE("Integer overflow", "[options]") options.parse_positional("positional"); CHECK_THROWS_AS(options.parse(argc, argv), cxxopts::argument_incorrect_type); } + +TEST_CASE("Floats", "[options]") +{ + cxxopts::Options options("parses_floats", "parses floats correctly"); + options.add_options() + ("double", "Double precision", cxxopts::value()) + ("positional", "Floats", cxxopts::value>()); + + Argv av({"floats", "--double", "0.5", "--", "4", "-4", "1.5e6", "-1.5e6"}); + + char** argv = av.argv(); + auto argc = av.argc(); + + options.parse_positional("positional"); + options.parse(argc, argv); + + REQUIRE(options.count("double") == 1); + REQUIRE(options.count("positional") == 4); + + CHECK(options["double"].as() == 0.5); + + auto& positional = options["positional"].as>(); + CHECK(positional[0] == 4); + CHECK(positional[1] == -4); + CHECK(positional[2] == 1.5e6); + CHECK(positional[3] == -1.5e6); +} +