mirror of
https://github.com/CLIUtils/CLI11.git
synced 2025-04-29 12:13:52 +00:00
Removing enum conversion
This commit is contained in:
parent
ef2d497fcb
commit
5d9a5636bc
@ -9,6 +9,7 @@ Note: This is the final release with `requires`, please switch to `needs`.
|
|||||||
* Support for `std::optional`, `std::experimental::optional`, and `boost::optional` added if `__has_include` is supported [#95]
|
* Support for `std::optional`, `std::experimental::optional`, and `boost::optional` added if `__has_include` is supported [#95]
|
||||||
* All macros/CMake variables now start with `CLI11_` instead of just `CLI_` [#95]
|
* All macros/CMake variables now start with `CLI11_` instead of just `CLI_` [#95]
|
||||||
* The internal stream was not being cleared before use in some cases. Fixed. [#95]
|
* The internal stream was not being cleared before use in some cases. Fixed. [#95]
|
||||||
|
* Using an emum now requires explicit conversion overload [#97]
|
||||||
|
|
||||||
Other, non-user facing changes:
|
Other, non-user facing changes:
|
||||||
|
|
||||||
@ -24,6 +25,7 @@ Other, non-user facing changes:
|
|||||||
[#90]: https://github.com/CLIUtils/CLI11/issues/90
|
[#90]: https://github.com/CLIUtils/CLI11/issues/90
|
||||||
[#92]: https://github.com/CLIUtils/CLI11/issues/92
|
[#92]: https://github.com/CLIUtils/CLI11/issues/92
|
||||||
[#95]: https://github.com/CLIUtils/CLI11/pull/95
|
[#95]: https://github.com/CLIUtils/CLI11/pull/95
|
||||||
|
[#97]: https://github.com/CLIUtils/CLI11/pull/97
|
||||||
|
|
||||||
|
|
||||||
## Version 1.4: More feedback
|
## Version 1.4: More feedback
|
||||||
|
@ -307,7 +307,11 @@ Also, in a related note, the `App` you get a pointer to is stored in the parent
|
|||||||
## How it works
|
## How it works
|
||||||
|
|
||||||
Every `add_` option you have seen so far depends on one method that takes a lambda function. Each of these methods is just making a different lambda function with capture to populate the option. The function has full access to the vector of strings, so it knows how many times an option was passed or how many arguments it received (flags add empty strings to keep the counts correct). The lambda returns `true` if it could validate the option strings, and
|
Every `add_` option you have seen so far depends on one method that takes a lambda function. Each of these methods is just making a different lambda function with capture to populate the option. The function has full access to the vector of strings, so it knows how many times an option was passed or how many arguments it received (flags add empty strings to keep the counts correct). The lambda returns `true` if it could validate the option strings, and
|
||||||
`false` if it failed. If you wanted to extend this to support a new type, just use a lambda. An example of a new parser for `complex<double>` that supports all of the features of a standard `add_options` call is in [one of the tests](./tests/NewParseTest.cpp). A simpler example is shown below:
|
`false` if it failed.
|
||||||
|
|
||||||
|
Other values can be added as long as they support `operator>>` (and defaults can be printed if they support `operator<<`). To add an enum, for example, provide a custom `operator>>` with an `istream` (inside the CLI namespace is fine if you don't want to interfere with an existing `operator>>`).
|
||||||
|
|
||||||
|
If you wanted to extend this to support a completely new type, just use a lambda. An example of a new parser for `complex<double>` that supports all of the features of a standard `add_options` call is in [one of the tests](./tests/NewParseTest.cpp). A simpler example is shown below:
|
||||||
|
|
||||||
### Example
|
### Example
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
# gives output on failed tests without having to set an environment variable.
|
# gives output on failed tests without having to set an environment variable.
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
set(gtest_force_shared_crt CACHE INTERNAL ON)
|
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||||
set(BUILD_SHARED_LIBS OFF)
|
set(BUILD_SHARED_LIBS OFF)
|
||||||
|
|
||||||
if(CMAKE_VERSION VERSION_LESS 3.11)
|
if(CMAKE_VERSION VERSION_LESS 3.11)
|
||||||
|
@ -1,12 +1,22 @@
|
|||||||
|
#include <sstream>
|
||||||
#include <CLI/CLI.hpp>
|
#include <CLI/CLI.hpp>
|
||||||
|
|
||||||
enum Level : std::int32_t { High, Medium, Low };
|
enum class Level : int { High, Medium, Low };
|
||||||
|
|
||||||
|
std::istream &operator>>(std::istream &in, Level &level) {
|
||||||
|
int i;
|
||||||
|
in >> i;
|
||||||
|
level = static_cast<Level>(i);
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream &operator<<(std::ostream &in, const Level &level) { return in << static_cast<int>(level); }
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
CLI::App app;
|
CLI::App app;
|
||||||
|
|
||||||
Level level;
|
Level level;
|
||||||
app.add_set("-l,--level", level, {High, Medium, Low}, "Level settings")
|
app.add_set("-l,--level", level, {Level::High, Level::Medium, Level::Low}, "Level settings")
|
||||||
->set_type_name("enum/Level in {High=0, Medium=1, Low=2}");
|
->set_type_name("enum/Level in {High=0, Medium=1, Low=2}");
|
||||||
|
|
||||||
CLI11_PARSE(app, argc, argv);
|
CLI11_PARSE(app, argc, argv);
|
||||||
|
@ -74,8 +74,7 @@ constexpr const char *type_name() {
|
|||||||
|
|
||||||
/// Signed integers / enums
|
/// Signed integers / enums
|
||||||
template <typename T,
|
template <typename T,
|
||||||
enable_if_t<(std::is_integral<T>::value && std::is_signed<T>::value) || std::is_enum<T>::value,
|
enable_if_t<(std::is_integral<T>::value && std::is_signed<T>::value), detail::enabler> = detail::dummy>
|
||||||
detail::enabler> = detail::dummy>
|
|
||||||
bool lexical_cast(std::string input, T &output) {
|
bool lexical_cast(std::string input, T &output) {
|
||||||
try {
|
try {
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
@ -124,7 +123,7 @@ bool lexical_cast(std::string input, T &output) {
|
|||||||
|
|
||||||
/// String and similar
|
/// String and similar
|
||||||
template <typename T,
|
template <typename T,
|
||||||
enable_if_t<!std::is_floating_point<T>::value && !std::is_integral<T>::value && !std::is_enum<T>::value &&
|
enable_if_t<!std::is_floating_point<T>::value && !std::is_integral<T>::value &&
|
||||||
std::is_assignable<T &, std::string>::value,
|
std::is_assignable<T &, std::string>::value,
|
||||||
detail::enabler> = detail::dummy>
|
detail::enabler> = detail::dummy>
|
||||||
bool lexical_cast(std::string input, T &output) {
|
bool lexical_cast(std::string input, T &output) {
|
||||||
@ -134,7 +133,7 @@ bool lexical_cast(std::string input, T &output) {
|
|||||||
|
|
||||||
/// Non-string parsable
|
/// Non-string parsable
|
||||||
template <typename T,
|
template <typename T,
|
||||||
enable_if_t<!std::is_floating_point<T>::value && !std::is_integral<T>::value && !std::is_enum<T>::value &&
|
enable_if_t<!std::is_floating_point<T>::value && !std::is_integral<T>::value &&
|
||||||
!std::is_assignable<T &, std::string>::value,
|
!std::is_assignable<T &, std::string>::value,
|
||||||
detail::enabler> = detail::dummy>
|
detail::enabler> = detail::dummy>
|
||||||
bool lexical_cast(std::string input, T &output) {
|
bool lexical_cast(std::string input, T &output) {
|
||||||
|
@ -321,8 +321,8 @@ TEST_F(TApp, ComplexOptMulti) {
|
|||||||
|
|
||||||
run();
|
run();
|
||||||
|
|
||||||
EXPECT_FLOAT_EQ(val.real(), 1);
|
EXPECT_DOUBLE_EQ(val.real(), 1);
|
||||||
EXPECT_FLOAT_EQ(val.imag(), 2);
|
EXPECT_DOUBLE_EQ(val.imag(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TApp, MissingValueNonRequiredOpt) {
|
TEST_F(TApp, MissingValueNonRequiredOpt) {
|
||||||
@ -643,26 +643,6 @@ TEST_F(TApp, NotRequiedExpectedDoubleShort) {
|
|||||||
EXPECT_THROW(run(), CLI::ArgumentMismatch);
|
EXPECT_THROW(run(), CLI::ArgumentMismatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TApp, EnumTest) {
|
|
||||||
enum Level : std::int32_t { High, Medium, Low };
|
|
||||||
Level level = Level::Low;
|
|
||||||
app.add_option("--level", level);
|
|
||||||
|
|
||||||
args = {"--level", "1"};
|
|
||||||
run();
|
|
||||||
EXPECT_EQ(level, Level::Medium);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(TApp, NewEnumTest) {
|
|
||||||
enum class Level2 : std::int32_t { High, Medium, Low };
|
|
||||||
Level2 level = Level2::Low;
|
|
||||||
app.add_option("--level", level);
|
|
||||||
|
|
||||||
args = {"--level", "1"};
|
|
||||||
run();
|
|
||||||
EXPECT_EQ(level, Level2::Medium);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(TApp, RequiredFlags) {
|
TEST_F(TApp, RequiredFlags) {
|
||||||
app.add_flag("-a")->required();
|
app.add_flag("-a")->required();
|
||||||
app.add_flag("-b")->mandatory(); // Alternate term
|
app.add_flag("-b")->mandatory(); // Alternate term
|
||||||
|
Loading…
x
Reference in New Issue
Block a user