diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 07ed55a4..75ba1e9b 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -203,6 +203,11 @@ add_test(NAME enum_fail COMMAND enum -l 4) set_property(TEST enum_fail PROPERTY PASS_REGULAR_EXPRESSION "--level: Check 4 value in {" "FAILED") +add_cli_exe(enum_ostream enum_ostream.cpp) +add_test(NAME enum_ostream_pass COMMAND enum_ostream --level medium) +set_property(TEST enum_ostream_pass PROPERTY PASS_REGULAR_EXPRESSION + "Enum received: Medium") + add_cli_exe(digit_args digit_args.cpp) add_test(NAME digit_args COMMAND digit_args -h) set_property(TEST digit_args PROPERTY PASS_REGULAR_EXPRESSION diff --git a/examples/enum_ostream.cpp b/examples/enum_ostream.cpp new file mode 100644 index 00000000..7e4be99f --- /dev/null +++ b/examples/enum_ostream.cpp @@ -0,0 +1,41 @@ +#include + +enum class Level : int { High, Medium, Low }; + +// this breaks the code +inline std::ostream &operator<<(std::ostream &o, const Level &l) { + switch(l) { + case Level::High: + o << "High"; + break; + case Level::Medium: + o << "Medium"; + break; + case Level::Low: + o << "Low"; + break; + } + return o; +} + +int main(int argc, char **argv) { + CLI::App app; + + Level level; + // specify string->value mappings + std::vector> map{ + {"high", Level::High}, {"medium", Level::Medium}, {"low", Level::Low}}; + // checked Transform does the translation and checks the results are either in one of the strings or one of the + // translations already + app.add_option("-l,--level", level, "Level settings") + ->required() + ->transform(CLI::CheckedTransformer(map, CLI::ignore_case)); + + CLI11_PARSE(app, argc, argv); + + // CLI11's built in enum streaming can be used outside CLI11 like this: + using namespace CLI::enums; + std::cout << "Enum received: " << level << std::endl; + + return 0; +} diff --git a/include/CLI/TypeTools.hpp b/include/CLI/TypeTools.hpp index 29e86957..0e8e5d9d 100644 --- a/include/CLI/TypeTools.hpp +++ b/include/CLI/TypeTools.hpp @@ -259,6 +259,22 @@ template ::value, detail::enabler> = detail::dummy> +std::string value_string(const T &value) { + return std::to_string(value); +} +/// get a string as a convertible value for enumerations +template ::value, detail::enabler> = detail::dummy> +std::string value_string(const T &value) { + return std::to_string(static_cast::type>(value)); +} +/// for other types just use the regular to_string function +template ::value && !std::is_arithmetic::value, detail::enabler> = detail::dummy> +auto value_string(const T &value) -> decltype(to_string(value)) { + return to_string(value); +} /// This will only trigger for actual void type template struct type_count { static const int value{0}; }; diff --git a/include/CLI/Validators.hpp b/include/CLI/Validators.hpp index 23936b51..93391a72 100644 --- a/include/CLI/Validators.hpp +++ b/include/CLI/Validators.hpp @@ -709,7 +709,7 @@ class IsMember : public Validator { if(res.first) { // Make sure the version in the input string is identical to the one in the set if(filter_fn) { - input = detail::to_string(detail::pair_adaptor::first(*(res.second))); + input = detail::value_string(detail::pair_adaptor::first(*(res.second))); } // Return empty error string (success) @@ -778,7 +778,7 @@ class Transformer : public Validator { } auto res = detail::search(mapping, b, filter_fn); if(res.first) { - input = detail::to_string(detail::pair_adaptor::second(*res.second)); + input = detail::value_string(detail::pair_adaptor::second(*res.second)); } return std::string{}; }; @@ -846,12 +846,12 @@ class CheckedTransformer : public Validator { } auto res = detail::search(mapping, b, filter_fn); if(res.first) { - input = detail::to_string(detail::pair_adaptor::second(*res.second)); + input = detail::value_string(detail::pair_adaptor::second(*res.second)); return std::string{}; } } for(const auto &v : detail::smart_deref(mapping)) { - auto output_string = detail::to_string(detail::pair_adaptor::second(v)); + auto output_string = detail::value_string(detail::pair_adaptor::second(v)); if(output_string == input) { return std::string(); }