mirror of
https://github.com/CLIUtils/CLI11.git
synced 2025-04-29 12:13:52 +00:00
Add better enum support in the library (#233)
* add some notes about enums in the readme add some helpers tests for enumerations Add better enum support in the library * fix Helpers Test for Enums
This commit is contained in:
parent
571fb07cfb
commit
6c645b55a1
@ -178,12 +178,12 @@ While all options internally are the same type, there are several ways to add an
|
|||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
app.add_option(option_name,
|
app.add_option(option_name,
|
||||||
variable_to_bind_to, // bool, int, float, vector, or string-like
|
variable_to_bind_to, // bool, int, float, vector, enum, or string-like
|
||||||
help_string="",
|
help_string="",
|
||||||
default=false)
|
default=false)
|
||||||
|
|
||||||
app.add_option_function<type>(option_name,
|
app.add_option_function<type>(option_name,
|
||||||
function <void(const type &value)>, // int, float, vector, or string-like
|
function <void(const type &value)>, // int, float, enum, vector, or string-like
|
||||||
help_string="")
|
help_string="")
|
||||||
|
|
||||||
app.add_complex(... // Special case: support for complex numbers
|
app.add_complex(... // Special case: support for complex numbers
|
||||||
|
@ -1,15 +1,13 @@
|
|||||||
#include <CLI/CLI.hpp>
|
#include <CLI/CLI.hpp>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
enum class Level : int { High, Medium, Low };
|
enum class Level : int { High, Medium, Low };
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
CLI::App app;
|
CLI::App app;
|
||||||
|
|
||||||
std::map<std::string, Level> map = {{"High", Level::High}, {"Medium", Level::Medium}, {"Low", Level::Low}};
|
|
||||||
|
|
||||||
Level level;
|
Level level;
|
||||||
|
std::map<std::string, Level> map = {{"High", Level::High}, {"Medium", Level::Medium}, {"Low", Level::Low}};
|
||||||
|
|
||||||
app.add_option("-l,--level", level, "Level settings")
|
app.add_option("-l,--level", level, "Level settings")
|
||||||
->required()
|
->required()
|
||||||
|
@ -27,10 +27,10 @@ inline std::string ini_join(std::vector<std::string> args) {
|
|||||||
auto it = std::find_if(arg.begin(), arg.end(), [](char ch) { return std::isspace<char>(ch, std::locale()); });
|
auto it = std::find_if(arg.begin(), arg.end(), [](char ch) { return std::isspace<char>(ch, std::locale()); });
|
||||||
if(it == arg.end())
|
if(it == arg.end())
|
||||||
s << arg;
|
s << arg;
|
||||||
else if(arg.find(R"(")") == std::string::npos)
|
else if(arg.find_first_of('\"') == std::string::npos)
|
||||||
s << R"(")" << arg << R"(")";
|
s << '\"' << arg << '\"';
|
||||||
else
|
else
|
||||||
s << R"(')" << arg << R"(')";
|
s << '\'' << arg << '\'';
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.str();
|
return s.str();
|
||||||
|
@ -46,7 +46,7 @@ inline std::vector<std::string> split(const std::string &s, char delim) {
|
|||||||
std::vector<std::string> elems;
|
std::vector<std::string> elems;
|
||||||
// Check to see if empty string, give consistent result
|
// Check to see if empty string, give consistent result
|
||||||
if(s.empty())
|
if(s.empty())
|
||||||
elems.emplace_back("");
|
elems.emplace_back();
|
||||||
else {
|
else {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss.str(s);
|
ss.str(s);
|
||||||
@ -70,6 +70,21 @@ template <typename T> std::string join(const T &v, std::string delim = ",") {
|
|||||||
return s.str();
|
return s.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Simple function to join a string from processed elements
|
||||||
|
template <typename T,
|
||||||
|
typename Callable,
|
||||||
|
typename = typename std::enable_if<!std::is_constructible<std::string, Callable>::value>::type>
|
||||||
|
std::string join(const T &v, Callable func, std::string delim = ",") {
|
||||||
|
std::ostringstream s;
|
||||||
|
size_t start = 0;
|
||||||
|
for(const auto &i : v) {
|
||||||
|
if(start++ > 0)
|
||||||
|
s << delim;
|
||||||
|
s << func(i);
|
||||||
|
}
|
||||||
|
return s.str();
|
||||||
|
}
|
||||||
|
|
||||||
/// Join a string in reverse order
|
/// Join a string in reverse order
|
||||||
template <typename T> std::string rjoin(const T &v, std::string delim = ",") {
|
template <typename T> std::string rjoin(const T &v, std::string delim = ",") {
|
||||||
std::ostringstream s;
|
std::ostringstream s;
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
// Distributed under the 3-Clause BSD License. See accompanying
|
// Distributed under the 3-Clause BSD License. See accompanying
|
||||||
// file LICENSE or https://github.com/CLIUtils/CLI11 for details.
|
// file LICENSE or https://github.com/CLIUtils/CLI11 for details.
|
||||||
|
|
||||||
|
#include "StringTools.hpp"
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -140,9 +141,16 @@ template <typename T, enable_if_t<is_vector<T>::value, detail::enabler> = detail
|
|||||||
constexpr const char *type_name() {
|
constexpr const char *type_name() {
|
||||||
return "VECTOR";
|
return "VECTOR";
|
||||||
}
|
}
|
||||||
|
/// Print name for enumeration types
|
||||||
|
template <typename T, enable_if_t<std::is_enum<T>::value, detail::enabler> = detail::dummy>
|
||||||
|
constexpr const char *type_name() {
|
||||||
|
return "ENUM";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Print for all other types
|
||||||
template <typename T,
|
template <typename T,
|
||||||
enable_if_t<!std::is_floating_point<T>::value && !std::is_integral<T>::value && !is_vector<T>::value,
|
enable_if_t<!std::is_floating_point<T>::value && !std::is_integral<T>::value && !is_vector<T>::value &&
|
||||||
|
!std::is_enum<T>::value,
|
||||||
detail::enabler> = detail::dummy>
|
detail::enabler> = detail::dummy>
|
||||||
constexpr const char *type_name() {
|
constexpr const char *type_name() {
|
||||||
return "TEXT";
|
return "TEXT";
|
||||||
@ -229,10 +237,22 @@ bool lexical_cast(std::string input, T &output) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// enumerations
|
||||||
|
template <typename T, enable_if_t<std::is_enum<T>::value, detail::enabler> = detail::dummy>
|
||||||
|
bool lexical_cast(std::string input, T &output) {
|
||||||
|
typename std::underlying_type<T>::type val;
|
||||||
|
bool retval = detail::lexical_cast(input, val);
|
||||||
|
if(!retval) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
output = static_cast<T>(val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// 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 &&
|
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 && !std::is_enum<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) {
|
||||||
std::istringstream is;
|
std::istringstream is;
|
||||||
|
@ -527,6 +527,10 @@ TEST(Types, TypeName) {
|
|||||||
|
|
||||||
std::string text2_name = CLI::detail::type_name<char *>();
|
std::string text2_name = CLI::detail::type_name<char *>();
|
||||||
EXPECT_EQ("TEXT", text2_name);
|
EXPECT_EQ("TEXT", text2_name);
|
||||||
|
|
||||||
|
enum class test { test1, test2, test3 };
|
||||||
|
std::string enum_name = CLI::detail::type_name<test>();
|
||||||
|
EXPECT_EQ("ENUM", enum_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Types, OverflowSmall) {
|
TEST(Types, OverflowSmall) {
|
||||||
@ -617,6 +621,25 @@ TEST(Types, LexicalCastParsable) {
|
|||||||
EXPECT_FALSE(CLI::detail::lexical_cast(extra_input, output));
|
EXPECT_FALSE(CLI::detail::lexical_cast(extra_input, output));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(Types, LexicalCastEnum) {
|
||||||
|
enum t1 : char { v1 = 5, v3 = 7, v5 = -9 };
|
||||||
|
|
||||||
|
t1 output;
|
||||||
|
EXPECT_TRUE(CLI::detail::lexical_cast("-9", output));
|
||||||
|
EXPECT_EQ(output, v5);
|
||||||
|
|
||||||
|
EXPECT_FALSE(CLI::detail::lexical_cast("invalid", output));
|
||||||
|
enum class t2 : uint64_t { enum1 = 65, enum2 = 45667, enum3 = 9999999999999 };
|
||||||
|
t2 output2;
|
||||||
|
EXPECT_TRUE(CLI::detail::lexical_cast("65", output2));
|
||||||
|
EXPECT_EQ(output2, t2::enum1);
|
||||||
|
|
||||||
|
EXPECT_FALSE(CLI::detail::lexical_cast("invalid", output2));
|
||||||
|
|
||||||
|
EXPECT_TRUE(CLI::detail::lexical_cast("9999999999999", output2));
|
||||||
|
EXPECT_EQ(output2, t2::enum3);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(FixNewLines, BasicCheck) {
|
TEST(FixNewLines, BasicCheck) {
|
||||||
std::string input = "one\ntwo";
|
std::string input = "one\ntwo";
|
||||||
std::string output = "one\n; two";
|
std::string output = "one\n; two";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user