CLI11 2.2.0
Loading...
Searching...
No Matches
CLI::detail Namespace Reference

Classes

struct  AppFriend
 This class is simply to allow tests access to App's protected functions. More...
 
struct  element_type
 not a pointer More...
 
struct  element_type< T, typename std::enable_if< is_copyable_ptr< T >::value >::type >
 
struct  element_value_type
 
class  ExistingDirectoryValidator
 Check for an existing directory (returns error message if check fails) More...
 
class  ExistingFileValidator
 Check for an existing file (returns error message if check fails) More...
 
class  ExistingPathValidator
 Check for an existing path. More...
 
struct  has_find
 
class  IPV4Validator
 Validate the given string is a legal ipv4 address. More...
 
class  is_complex
 Check for complex. More...
 
class  is_direct_constructible
 
class  is_istreamable
 Check for input streamability. More...
 
struct  is_mutable_container
 
struct  is_mutable_container< T, conditional_t< false, void_t< typename T::value_type, decltype(std::declval< T >().end()), decltype(std::declval< T >().clear()), decltype(std::declval< T >().insert(std::declval< decltype(std::declval< T >().end())>(), std::declval< const typename T::value_type & >()))>, void > >
 
class  is_ostreamable
 
struct  is_readable_container
 
struct  is_readable_container< T, conditional_t< false, void_t< decltype(std::declval< T >().end()), decltype(std::declval< T >().begin())>, void > >
 
class  is_tuple_like
 
struct  is_wrapper
 
struct  is_wrapper< T, conditional_t< false, void_t< typename T::value_type >, void > >
 
class  NonexistentPathValidator
 Check for an non-existing path. More...
 
struct  pair_adaptor
 Adaptor for set-like structure: This just wraps a normal container in a few utilities that do almost nothing. More...
 
struct  pair_adaptor< T, conditional_t< false, void_t< typename T::value_type::first_type, typename T::value_type::second_type >, void > >
 
struct  subtype_count
 Set of overloads to get the type size of an object. More...
 
struct  subtype_count_min
 forward declare the subtype_count_min structure More...
 
struct  type_count
 This will only trigger for actual void type. More...
 
struct  type_count< T, typename std::enable_if< is_complex< T >::value >::type >
 Type size for complex since it sometimes looks like a wrapper. More...
 
struct  type_count< T, typename std::enable_if< is_mutable_container< T >::value >::type >
 Type size of types that are wrappers,except complex and tuples(which can also be wrappers sometimes) More...
 
struct  type_count< T, typename std::enable_if< is_wrapper< T >::value &&!is_complex< T >::value &&!is_tuple_like< T >::value &&!is_mutable_container< T >::value >::type >
 Type size of types that are wrappers,except containers complex and tuples(which can also be wrappers sometimes) More...
 
struct  type_count< T, typename std::enable_if<!is_wrapper< T >::value &&!is_tuple_like< T >::value &&!is_complex< T >::value &&!std::is_void< T >::value >::type >
 Type size for regular object types that do not look like a tuple. More...
 
struct  type_count_base
 This will only trigger for actual void type. More...
 
struct  type_count_base< T, typename std::enable_if< is_mutable_container< T >::value >::type >
 Type count base for containers is the type_count_base of the individual element. More...
 
struct  type_count_base< T, typename std::enable_if< is_tuple_like< T >::value &&!is_mutable_container< T >::value >::type >
 the base tuple size More...
 
struct  type_count_base< T, typename std::enable_if<!is_tuple_like< T >::value &&!is_mutable_container< T >::value &&!std::is_void< T >::value >::type >
 Type size for regular object types that do not look like a tuple. More...
 
struct  wrapped_type
 template to get the underlying value type if it exists or use a default More...
 
struct  wrapped_type< T, def, typename std::enable_if< is_wrapper< T >::value >::type >
 Type size for regular object types that do not look like a tuple. More...
 

Enumerations

enum class  Classifier {
  NONE , POSITIONAL_MARK , SHORT , LONG ,
  WINDOWS_STYLE , SUBCOMMAND , SUBCOMMAND_TERMINATOR
}
 
enum class  enabler
 Simple empty scoped class. More...
 
enum class  path_type { nonexistent , file , directory }
 CLI enumeration of different file types. More...
 

Functions

template<typename T , enable_if_t<!std::is_integral< T >::value||(sizeof(T)<=1U), detail::enabler > = detail::dummy>
Optiondefault_flag_modifiers (Option *opt)
 helper functions for adding in appropriate flag modifiers for add_flag
 
std::string convert_arg_for_ini (const std::string &arg, char stringQuote='"', char characterQuote = '\'')
 
std::string ini_join (const std::vector< std::string > &args, char sepChar=',', char arrayStart='[', char arrayEnd=']', char stringQuote='"', char characterQuote = '\'')
 Comma separated join, adds quotes if needed.
 
std::vector< std::string > generate_parents (const std::string &section, std::string &name, char parentSeparator)
 
void checkParentSegments (std::vector< ConfigItem > &output, const std::string &currentSection, char parentSeparator)
 assuming non default segments do a check on the close and open of the segments in a configItem structure
 
bool split_short (const std::string &current, std::string &name, std::string &rest)
 
bool split_long (const std::string &current, std::string &name, std::string &value)
 
bool split_windows_style (const std::string &current, std::string &name, std::string &value)
 
std::vector< std::string > split_names (std::string current)
 
std::vector< std::pair< std::string, std::string > > get_default_flag_values (const std::string &str)
 extract default flag values either {def} or starting with a !
 
std::tuple< std::vector< std::string >, std::vector< std::string >, std::string > get_names (const std::vector< std::string > &input)
 Get a vector of short names, one of long names, and a single name.
 
std::vector< std::string > split (const std::string &s, char delim)
 Split a string by a delim.
 
template<typename T >
std::string join (const T &v, std::string delim=",")
 Simple function to join a string.
 
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=",")
 Simple function to join a string from processed elements.
 
template<typename T >
std::string rjoin (const T &v, std::string delim=",")
 Join a string in reverse order.
 
std::string & ltrim (std::string &str)
 Trim whitespace from left of string.
 
std::string & ltrim (std::string &str, const std::string &filter)
 Trim anything from left of string.
 
std::string & rtrim (std::string &str)
 Trim whitespace from right of string.
 
std::string & rtrim (std::string &str, const std::string &filter)
 Trim anything from right of string.
 
std::string & trim (std::string &str)
 Trim whitespace from string.
 
std::string & trim (std::string &str, const std::string filter)
 Trim anything from string.
 
std::string trim_copy (const std::string &str)
 Make a copy of the string and then trim it.
 
std::string & remove_quotes (std::string &str)
 remove quotes at the front and back of a string either '"' or '\''
 
std::string fix_newlines (const std::string &leader, std::string input)
 
std::string trim_copy (const std::string &str, const std::string &filter)
 Make a copy of the string and then trim it, any filter string can be used (any char in string is filtered)
 
std::ostream & format_help (std::ostream &out, std::string name, const std::string &description, std::size_t wid)
 Print a two part "help" string.
 
std::ostream & format_aliases (std::ostream &out, const std::vector< std::string > &aliases, std::size_t wid)
 Print subcommand aliases.
 
template<typename T >
bool valid_first_char (T c)
 
template<typename T >
bool valid_later_char (T c)
 Verify following characters of an option.
 
bool valid_name_string (const std::string &str)
 Verify an option/subcommand name.
 
bool valid_alias_name_string (const std::string &str)
 Verify an app name.
 
bool is_separator (const std::string &str)
 check if a string is a container segment separator (empty or "%%")
 
bool isalpha (const std::string &str)
 Verify that str consists of letters only.
 
std::string to_lower (std::string str)
 Return a lower case version of a string.
 
std::string remove_underscore (std::string str)
 remove underscores from a string
 
std::string find_and_replace (std::string str, std::string from, std::string to)
 Find and replace a substring with another substring.
 
bool has_default_flag_values (const std::string &flags)
 check if the flag definitions has possible false flags
 
void remove_default_flag_values (std::string &flags)
 
std::ptrdiff_t find_member (std::string name, const std::vector< std::string > names, bool ignore_case=false, bool ignore_underscore=false)
 Check if a string is a member of a list of strings and optionally ignore case or ignore underscores.
 
template<typename Callable >
std::string find_and_modify (std::string str, std::string trigger, Callable modify)
 
 trim (str)
 
 while (!str.empty())
 
template<typename T , enable_if_t< is_istreamable< T >::value, detail::enabler > = detail::dummy>
bool from_stream (const std::string &istring, T &obj)
 Templated operation to get a value from a stream.
 
template<typename T , enable_if_t< std::is_convertible< T, std::string >::value, detail::enabler > = detail::dummy>
auto to_string (T &&value) -> decltype(std::forward< T >(value))
 Convert an object to a string (directly forward if this can become a string)
 
template<typename T , enable_if_t< std::is_constructible< std::string, T >::value &&!std::is_convertible< T, std::string >::value, detail::enabler > = detail::dummy>
std::string to_string (const T &value)
 Construct a string from the object.
 
template<typename T , enable_if_t<!std::is_convertible< std::string, T >::value &&!std::is_constructible< std::string, T >::value &&is_ostreamable< T >::value, detail::enabler > = detail::dummy>
std::string to_string (T &&value)
 Convert an object to a string (streaming must be supported for that type)
 
template<typename T1 , typename T2 , typename T , enable_if_t< std::is_same< T1, T2 >::value, detail::enabler > = detail::dummy>
auto checked_to_string (T &&value) -> decltype(to_string(std::forward< T >(value)))
 special template overload
 
template<typename T1 , typename T2 , typename T , enable_if_t<!std::is_same< T1, T2 >::value, detail::enabler > = detail::dummy>
std::string checked_to_string (T &&)
 special template overload
 
template<typename T , enable_if_t< std::is_arithmetic< T >::value, detail::enabler > = detail::dummy>
std::string value_string (const T &value)
 get a string as a convertible value for arithmetic types
 
template<typename T , enable_if_t<!std::is_enum< T >::value &&!std::is_arithmetic< T >::value, detail::enabler > = detail::dummy>
auto value_string (const T &value) -> decltype(to_string(value))
 for other types just use the regular to_string function
 
template<typename T , std::size_t I>
constexpr std::enable_if< I==type_count_base< T >::value, int >::type tuple_type_size ()
 0 if the index > tuple size
 
template<typename T , std::size_t I>
constexpr std::enable_if< I< type_count_base< T >::value, int >::type tuple_type_size() { return subtype_count< typename std::tuple_element< I, T >::type >::value+tuple_type_size< T, I+1 >();}template< typename T > struct type_count< T, typename std::enable_if< is_tuple_like< T >::value >::type > { static constexpr int value{tuple_type_size< T, 0 >()};};template< typename T > struct subtype_count { static constexpr int value{is_mutable_container< T >::value ? expected_max_vector_size :type_count< T >::value};};template< typename T, typename Enable=void > struct type_count_min { static const int value{0};};template< typename T >struct type_count_min< T, typename std::enable_if<!is_mutable_container< T >::value &&!is_tuple_like< T >::value &&!is_wrapper< T >::value &&!is_complex< T >::value &&!std::is_void< T >::value >::type > { static constexpr int value{type_count< T >::value};};template< typename T > struct type_count_min< T, typename std::enable_if< is_complex< T >::value >::type > { static constexpr int value{1};};template< typename T >struct type_count_min< T, typename std::enable_if< is_wrapper< T >::value &&!is_complex< T >::value &&!is_tuple_like< T >::value >::type > { static constexpr int value{subtype_count_min< typename T::value_type >::value};};template< typename T, std::size_t I >constexpr typename std::enable_if< I==type_count_base< T >::value, int >::type tuple_type_size_min() { return 0;}template< typename T, std::size_t I > constexpr typename std::enable_if< I< type_count_base< T >::value, int >::type tuple_type_size_min() { return subtype_count_min< typename std::tuple_element< I, T >::type >::value+tuple_type_size_min< T, I+1 >();}template< typename T > struct type_count_min< T, typename std::enable_if< is_tuple_like< T >::value >::type > { static constexpr int value{tuple_type_size_min< T, 0 >()};};template< typename T > struct subtype_count_min { static constexpr int value{is_mutable_container< T >::value ?((type_count< T >::value< expected_max_vector_size) ? type_count< T >::value :0) :type_count_min< T >::value};};template< typename T, typename Enable=void > struct expected_count { static const int value{0};};template< typename T >struct expected_count< T, typename std::enable_if<!is_mutable_container< T >::value &&!is_wrapper< T >::value &&!std::is_void< T >::value >::type > { static constexpr int value{1};};template< typename T > struct expected_count< T, typename std::enable_if< is_mutable_container< T >::value >::type > { static constexpr int value{expected_max_vector_size};};template< typename T >struct expected_count< T, typename std::enable_if<!is_mutable_container< T >::value &&is_wrapper< T >::value >::type > { static constexpr int value{expected_count< typename T::value_type >::value};};enum class object_category :int { char_value=1, integral_value=2, unsigned_integral=4, enumeration=6, boolean_value=8, floating_point=10, number_constructible=12, double_constructible=14, integer_constructible=16, string_assignable=23, string_constructible=24, other=45, wrapper_value=50, complex_number=60, tuple_value=70, container_value=80,};template< typename T, typename Enable=void > struct classify_object { static constexpr object_category value{object_category::other};};template< typename T >struct classify_object< T, typename std::enable_if< std::is_integral< T >::value &&!std::is_same< T, char >::value &&std::is_signed< T >::value &&!is_bool< T >::value &&!std::is_enum< T >::value >::type > { static constexpr object_category value{object_category::integral_value};};template< typename T >struct classify_object< T, typename std::enable_if< std::is_integral< T >::value &&std::is_unsigned< T >::value &&!std::is_same< T, char >::value &&!is_bool< T >::value >::type > { static constexpr object_category value{object_category::unsigned_integral};};template< typename T >struct classify_object< T, typename std::enable_if< std::is_same< T, char >::value &&!std::is_enum< T >::value >::type > { static constexpr object_category value{object_category::char_value};};template< typename T > struct classify_object< T, typename std::enable_if< is_bool< T >::value >::type > { static constexpr object_category value{object_category::boolean_value};};template< typename T > struct classify_object< T, typename std::enable_if< std::is_floating_point< T >::value >::type > { static constexpr object_category value{object_category::floating_point};};template< typename T >struct classify_object< T, typename std::enable_if<!std::is_floating_point< T >::value &&!std::is_integral< T >::value &&std::is_assignable< T &, std::string >::value >::type > { static constexpr object_category value{object_category::string_assignable};};template< typename T >struct classify_object< T, typename std::enable_if<!std::is_floating_point< T >::value &&!std::is_integral< T >::value &&!std::is_assignable< T &, std::string >::value &&(type_count< T >::value==1) &&std::is_constructible< T, std::string >::value >::type > { static constexpr object_category value{object_category::string_constructible};};template< typename T > struct classify_object< T, typename std::enable_if< std::is_enum< T >::value >::type > { static constexpr object_category value{object_category::enumeration};};template< typename T > struct classify_object< T, typename std::enable_if< is_complex< T >::value >::type > { static constexpr object_category value{object_category::complex_number};};template< typename T > struct uncommon_type { using type=typename std::conditional<!std::is_floating_point< T >::value &&!std::is_integral< T >::value &&!std::is_assignable< T &, std::string >::value &&!std::is_constructible< T, std::string >::value &&!is_complex< T >::value &&!is_mutable_container< T >::value &&!std::is_enum< T >::value, std::true_type, std::false_type >::type;static constexpr bool value=type::value;};template< typename T >struct classify_object< T, typename std::enable_if<(!is_mutable_container< T >::value &&is_wrapper< T >::value &&!is_tuple_like< T >::value &&uncommon_type< T >::value)>::type > { static constexpr object_category value{object_category::wrapper_value};};template< typename T >struct classify_object< T, typename std::enable_if< uncommon_type< T >::value &&type_count< T >::value==1 &&!is_wrapper< T >::value &&is_direct_constructible< T, double >::value &&is_direct_constructible< T, int >::value >::type > { static constexpr object_category value{object_category::number_constructible};};template< typename T >struct classify_object< T, typename std::enable_if< uncommon_type< T >::value &&type_count< T >::value==1 &&!is_wrapper< T >::value &&!is_direct_constructible< T, double >::value &&is_direct_constructible< T, int >::value >::type > { static constexpr object_category value{object_category::integer_constructible};};template< typename T >struct classify_object< T, typename std::enable_if< uncommon_type< T >::value &&type_count< T >::value==1 &&!is_wrapper< T >::value &&is_direct_constructible< T, double >::value &&!is_direct_constructible< T, int >::value >::type > { static constexpr object_category value{object_category::double_constructible};};template< typename T >struct classify_object< T, typename std::enable_if< is_tuple_like< T >::value &&((type_count< T >::value >=2 &&!is_wrapper< T >::value)||(uncommon_type< T >::value &&!is_direct_constructible< T, double >::value &&!is_direct_constructible< T, int >::value))>::type > { static constexpr object_category value{object_category::tuple_value};};template< typename T > struct classify_object< T, typename std::enable_if< is_mutable_container< T >::value >::type > { static constexpr object_category value{object_category::container_value};};template< typename T, enable_if_t< classify_object< T >::value==object_category::char_value, detail::enabler >=detail::dummy >constexpr const char *type_name() { return "CHAR";}template< typename T, enable_if_t< classify_object< T >::value==object_category::integral_value||classify_object< T >::value==object_category::integer_constructible, detail::enabler >=detail::dummy >constexpr const char *type_name() { return "INT";}template< typename T, enable_if_t< classify_object< T >::value==object_category::unsigned_integral, detail::enabler >=detail::dummy >constexpr const char *type_name() { return "UINT";}template< typename T, enable_if_t< classify_object< T >::value==object_category::floating_point||classify_object< T >::value==object_category::number_constructible||classify_object< T >::value==object_category::double_constructible, detail::enabler >=detail::dummy >constexpr const char *type_name() { return "FLOAT";}template< typename T, enable_if_t< classify_object< T >::value==object_category::enumeration, detail::enabler >=detail::dummy >constexpr const char *type_name() { return "ENUM";}template< typename T, enable_if_t< classify_object< T >::value==object_category::boolean_value, detail::enabler >=detail::dummy >constexpr const char *type_name() { return "BOOLEAN";}template< typename T, enable_if_t< classify_object< T >::value==object_category::complex_number, detail::enabler >=detail::dummy >constexpr const char *type_name() { return "COMPLEX";}template< typename T, enable_if_t< classify_object< T >::value >=object_category::string_assignable &&classify_object< T >::value<=object_category::other, detail::enabler >=detail::dummy >constexpr const char *type_name() { return "TEXT";}template< typename T, enable_if_t< classify_object< T >::value==object_category::tuple_value &&type_count_base< T >::value >=2, detail::enabler >=detail::dummy >std::string type_name();template< typename T, enable_if_t< classify_object< T >::value==object_category::container_value||classify_object< T >::value==object_category::wrapper_value, detail::enabler >=detail::dummy >std::string type_name();template< typename T, enable_if_t< classify_object< T >::value==object_category::tuple_value &&type_count_base< T >::value==1, detail::enabler >=detail::dummy >inline std::string type_name() { return type_name< typename std::decay< typename std::tuple_element< 0, T >::type >::type >();}template< typename T, std::size_t I >inline typename std::enable_if< I==type_count_base< T >::value, std::string >::type tuple_name() { return std::string{};}template< typename T, std::size_t I >inline typename std::enable_if<(I< type_count_base< T >::value), std::string >::type tuple_name() { std::string str=std::string(type_name< typename std::decay< typename std::tuple_element< I, T >::type >::type >())+','+tuple_name< T, I+1 >();if(str.back()==',') str.pop_back();return str;}template< typename T, enable_if_t< classify_object< T >::value==object_category::tuple_value &&type_count_base< T >::value >=2, detail::enabler > >inline std::string type_name() { auto tname=std::string(1, '[')+tuple_name< T, 0 >();tname.push_back(']');return tname;}template< typename T, enable_if_t< classify_object< T >::value==object_category::container_value||classify_object< T >::value==object_category::wrapper_value, detail::enabler > >inline std::string type_name() { return type_name< typename T::value_type >();}template< typename T, enable_if_t< std::is_unsigned< T >::value, detail::enabler >=detail::dummy >bool integral_conversion(const std::string &input, T &output) noexcept { if(input.empty()) { return false;} char *val=nullptr;std::uint64_t output_ll=std::strtoull(input.c_str(), &val, 0);output=static_cast< T >(output_ll);if(val==(input.c_str()+input.size()) &&static_cast< std::uint64_t >(output)==output_ll) { return true;} val=nullptr;std::int64_t output_sll=std::strtoll(input.c_str(), &val, 0);if(val==(input.c_str()+input.size())) { output=(output_sll< 0) ? static_cast< T >(0) return (static_cast< std::int64_t >(output)==output_sll)
 Recursively generate the tuple type name.
 
template<typename T , enable_if_t< std::is_signed< T >::value, detail::enabler > = detail::dummy>
bool integral_conversion (const std::string &input, T &output) noexcept
 Convert to a signed integral.
 
std::int64_t to_flag_value (std::string val)
 Convert a flag into an integer value typically binary flags.
 
template<typename T , enable_if_t< classify_object< T >::value==object_category::integral_value||classify_object< T >::value==object_category::unsigned_integral, detail::enabler > = detail::dummy>
bool lexical_cast (const std::string &input, T &output)
 Integer conversion.
 
template<typename AssignTo , typename ConvertTo , enable_if_t< std::is_same< AssignTo, ConvertTo >::value &&(classify_object< AssignTo >::value==object_category::string_assignable||classify_object< AssignTo >::value==object_category::string_constructible), detail::enabler > = detail::dummy>
bool lexical_assign (const std::string &input, AssignTo &output)
 Assign a value through lexical cast operations.
 
path_type check_path (const char *file) noexcept
 get the type of the path from a file name
 
template<typename T , enable_if_t< is_copyable_ptr< typename std::remove_reference< T >::type >::value, detail::enabler > = detail::dummy>
auto smart_deref (T value) -> decltype(*value)
 
template<typename T , enable_if_t<!is_copyable_ptr< typename std::remove_reference< T >::type >::value, detail::enabler > = detail::dummy>
std::remove_reference< T >::type & smart_deref (T &value)
 
template<typename T >
std::string generate_set (const T &set)
 Generate a string representation of a set.
 
template<typename T >
std::string generate_map (const T &map, bool key_only=false)
 Generate a string representation of a map.
 
template<typename T , typename V , enable_if_t<!has_find< T, V >::value, detail::enabler > = detail::dummy>
auto search (const T &set, const V &val) -> std::pair< bool, decltype(std::begin(detail::smart_deref(set)))>
 A search function.
 
template<typename T , typename V >
auto search (const T &set, const V &val, const std::function< V(V)> &filter_function) -> std::pair< bool, decltype(std::begin(detail::smart_deref(set)))>
 A search function with a filter function.
 
template<typename T >
std::enable_if< std::is_signed< T >::value, T >::type overflowCheck (const T &a, const T &b)
 Do a check for overflow on signed numbers.
 
template<typename T >
std::enable_if<!std::is_signed< T >::value, T >::type overflowCheck (const T &a, const T &b)
 Do a check for overflow on unsigned numbers.
 
template<typename T >
std::enable_if< std::is_integral< T >::value, bool >::type checked_multiply (T &a, T b)
 Performs a *= b; if it doesn't cause integer overflow. Returns false otherwise.
 
template<typename T >
std::enable_if< std::is_floating_point< T >::value, bool >::type checked_multiply (T &a, T b)
 Performs a *= b; if it doesn't equal infinity. Returns false otherwise.
 
std::pair< std::string, std::string > split_program_name (std::string commandline)
 

Variables

constexpr int expected_max_vector_size {1 << 29}
 
auto find_ws
 
std::vector< std::string > output
 
bool embeddedQuote = false
 
char keyChar = ' '
 
constexpr enabler dummy = {}
 An instance to use in EnableIf.
 
return false
 

Enumeration Type Documentation

◆ Classifier

enum class CLI::detail::Classifier
strong
Enumerator
NONE 
POSITIONAL_MARK 
SHORT 
LONG 
WINDOWS_STYLE 
SUBCOMMAND 
SUBCOMMAND_TERMINATOR 

◆ enabler

enum class CLI::detail::enabler
strong

Simple empty scoped class.

◆ path_type

enum class CLI::detail::path_type
strong

CLI enumeration of different file types.

Enumerator
nonexistent 
file 
directory 

Function Documentation

◆ check_path()

path_type CLI::detail::check_path ( const char * file)
inlinenoexcept

get the type of the path from a file name

◆ checked_multiply() [1/2]

template<typename T >
std::enable_if< std::is_integral< T >::value, bool >::type CLI::detail::checked_multiply ( T & a,
T b )

Performs a *= b; if it doesn't cause integer overflow. Returns false otherwise.

◆ checked_multiply() [2/2]

template<typename T >
std::enable_if< std::is_floating_point< T >::value, bool >::type CLI::detail::checked_multiply ( T & a,
T b )

Performs a *= b; if it doesn't equal infinity. Returns false otherwise.

◆ checked_to_string() [1/2]

template<typename T1 , typename T2 , typename T , enable_if_t<!std::is_same< T1, T2 >::value, detail::enabler > = detail::dummy>
std::string CLI::detail::checked_to_string ( T && )

special template overload

◆ checked_to_string() [2/2]

template<typename T1 , typename T2 , typename T , enable_if_t< std::is_same< T1, T2 >::value, detail::enabler > = detail::dummy>
auto CLI::detail::checked_to_string ( T && value) -> decltype(to_string(std::forward<T>(value)))

special template overload

◆ checkParentSegments()

void CLI::detail::checkParentSegments ( std::vector< ConfigItem > & output,
const std::string & currentSection,
char parentSeparator )
inline

assuming non default segments do a check on the close and open of the segments in a configItem structure

◆ convert_arg_for_ini()

std::string CLI::detail::convert_arg_for_ini ( const std::string & arg,
char stringQuote = '"',
char characterQuote = '\'' )
inline

◆ default_flag_modifiers()

template<typename T , enable_if_t<!std::is_integral< T >::value||(sizeof(T)<=1U), detail::enabler > = detail::dummy>
Option * CLI::detail::default_flag_modifiers ( Option * opt)

helper functions for adding in appropriate flag modifiers for add_flag

summing modifiers

◆ find_and_modify()

template<typename Callable >
std::string CLI::detail::find_and_modify ( std::string str,
std::string trigger,
Callable modify )
inline

Find a trigger string and call a modify callable function that takes the current string and starting position of the trigger and returns the position in the string to search for the next trigger string

◆ find_and_replace()

std::string CLI::detail::find_and_replace ( std::string str,
std::string from,
std::string to )
inline

Find and replace a substring with another substring.

◆ find_member()

std::ptrdiff_t CLI::detail::find_member ( std::string name,
const std::vector< std::string > names,
bool ignore_case = false,
bool ignore_underscore = false )
inline

Check if a string is a member of a list of strings and optionally ignore case or ignore underscores.

◆ fix_newlines()

std::string CLI::detail::fix_newlines ( const std::string & leader,
std::string input )
inline

Add a leader to the beginning of all new lines (nothing is added at the start of the first line). "; " would be for ini files

Can't use Regex, or this would be a subs.

◆ format_aliases()

std::ostream & CLI::detail::format_aliases ( std::ostream & out,
const std::vector< std::string > & aliases,
std::size_t wid )
inline

Print subcommand aliases.

◆ format_help()

std::ostream & CLI::detail::format_help ( std::ostream & out,
std::string name,
const std::string & description,
std::size_t wid )
inline

Print a two part "help" string.

◆ from_stream()

template<typename T , enable_if_t< is_istreamable< T >::value, detail::enabler > = detail::dummy>
bool CLI::detail::from_stream ( const std::string & istring,
T & obj )

Templated operation to get a value from a stream.

◆ generate_map()

template<typename T >
std::string CLI::detail::generate_map ( const T & map,
bool key_only = false )

Generate a string representation of a map.

◆ generate_parents()

std::vector< std::string > CLI::detail::generate_parents ( const std::string & section,
std::string & name,
char parentSeparator )
inline

◆ generate_set()

template<typename T >
std::string CLI::detail::generate_set ( const T & set)

Generate a string representation of a set.

◆ get_default_flag_values()

std::vector< std::pair< std::string, std::string > > CLI::detail::get_default_flag_values ( const std::string & str)
inline

extract default flag values either {def} or starting with a !

◆ get_names()

std::tuple< std::vector< std::string >, std::vector< std::string >, std::string > CLI::detail::get_names ( const std::vector< std::string > & input)
inline

Get a vector of short names, one of long names, and a single name.

◆ has_default_flag_values()

bool CLI::detail::has_default_flag_values ( const std::string & flags)
inline

check if the flag definitions has possible false flags

◆ ini_join()

std::string CLI::detail::ini_join ( const std::vector< std::string > & args,
char sepChar = ',',
char arrayStart = '[',
char arrayEnd = ']',
char stringQuote = '"',
char characterQuote = '\'' )
inline

Comma separated join, adds quotes if needed.

◆ integral_conversion()

template<typename T , enable_if_t< std::is_signed< T >::value, detail::enabler > = detail::dummy>
bool CLI::detail::integral_conversion ( const std::string & input,
T & output )
noexcept

Convert to a signed integral.

◆ is_separator()

bool CLI::detail::is_separator ( const std::string & str)
inline

check if a string is a container segment separator (empty or "%%")

◆ isalpha()

bool CLI::detail::isalpha ( const std::string & str)
inline

Verify that str consists of letters only.

◆ join() [1/2]

template<typename T , typename Callable , typename = typename std::enable_if<!std::is_constructible<std::string, Callable>::value>::type>
std::string CLI::detail::join ( const T & v,
Callable func,
std::string delim = "," )

Simple function to join a string from processed elements.

◆ join() [2/2]

template<typename T >
std::string CLI::detail::join ( const T & v,
std::string delim = "," )

Simple function to join a string.

◆ lexical_assign()

template<typename AssignTo , typename ConvertTo , enable_if_t< std::is_same< AssignTo, ConvertTo >::value &&(classify_object< AssignTo >::value==object_category::string_assignable||classify_object< AssignTo >::value==object_category::string_constructible), detail::enabler > = detail::dummy>
bool CLI::detail::lexical_assign ( const std::string & input,
AssignTo & output )

Assign a value through lexical cast operations.

Assign a value from a lexical cast through constructing a value and move assigning it.

Assign a value converted from a string in lexical cast to the output value directly.

Assign a value through lexical cast operations Strings can be empty so we need to do a little different

Assign a value through lexical cast operations for int compatible values mainly for atomic operations on some compilers

◆ lexical_cast()

template<typename T , enable_if_t< classify_object< T >::value==object_category::integral_value||classify_object< T >::value==object_category::unsigned_integral, detail::enabler > = detail::dummy>
bool CLI::detail::lexical_cast ( const std::string & input,
T & output )

Integer conversion.

Non-string parsable by a stream.

Non-string convertible from an int.

Assignable from double.

Assignable from int.

Assignable from double or int.

wrapper types

Enumerations.

String and similar constructible and copy assignment.

String and similar direct assignment.

complex

Floats.

Boolean values.

char values

◆ ltrim() [1/2]

std::string & CLI::detail::ltrim ( std::string & str)
inline

Trim whitespace from left of string.

◆ ltrim() [2/2]

std::string & CLI::detail::ltrim ( std::string & str,
const std::string & filter )
inline

Trim anything from left of string.

◆ overflowCheck() [1/2]

template<typename T >
std::enable_if< std::is_signed< T >::value, T >::type CLI::detail::overflowCheck ( const T & a,
const T & b )
inline

Do a check for overflow on signed numbers.

◆ overflowCheck() [2/2]

template<typename T >
std::enable_if<!std::is_signed< T >::value, T >::type CLI::detail::overflowCheck ( const T & a,
const T & b )
inline

Do a check for overflow on unsigned numbers.

◆ remove_default_flag_values()

void CLI::detail::remove_default_flag_values ( std::string & flags)
inline

◆ remove_quotes()

std::string & CLI::detail::remove_quotes ( std::string & str)
inline

remove quotes at the front and back of a string either '"' or '\''

◆ remove_underscore()

std::string CLI::detail::remove_underscore ( std::string str)
inline

remove underscores from a string

◆ return()

template<typename T , std::size_t I>
std::enable_if< I< type_count_base< T >::value, int >::type tuple_type_size() { return subtype_count< typename std::tuple_element< I, T >::type >::value+tuple_type_size< T, I+1 >();}template< typename T > struct type_count< T, typename std::enable_if< is_tuple_like< T >::value >::type > { static constexpr int value{tuple_type_size< T, 0 >()};};template< typename T > struct subtype_count { static constexpr int value{is_mutable_container< T >::value ? expected_max_vector_size :type_count< T >::value};};template< typename T, typename Enable=void > struct type_count_min { static const int value{0};};template< typename T >struct type_count_min< T, typename std::enable_if<!is_mutable_container< T >::value &&!is_tuple_like< T >::value &&!is_wrapper< T >::value && !is_complex< T >::value &&!std::is_void< T >::value >::type > { static constexpr int value{type_count< T >::value};};template< typename T > struct type_count_min< T, typename std::enable_if< is_complex< T >::value >::type > { static constexpr int value{1};};template< typename T >struct type_count_min< T, typename std::enable_if< is_wrapper< T >::value &&!is_complex< T >::value &&!is_tuple_like< T >::value >::type > { static constexpr int value{subtype_count_min< typename T::value_type >::value};};template< typename T, std::size_t I >constexpr typename std::enable_if< I==type_count_base< T >::value, int >::type tuple_type_size_min() { return 0;}template< typename T, std::size_t I > constexpr typename std::enable_if< I< type_count_base< T >::value, int >::type tuple_type_size_min() { return subtype_count_min< typename std::tuple_element< I, T >::type >::value+tuple_type_size_min< T, I+1 >();}template< typename T > struct type_count_min< T, typename std::enable_if< is_tuple_like< T >::value >::type > { static constexpr int value{tuple_type_size_min< T, 0 >()};};template< typename T > struct subtype_count_min { static constexpr int value{is_mutable_container< T >::value ?((type_count< T >::value< expected_max_vector_size) ? type_count< T >::value :0) :type_count_min< T >::value};};template< typename T, typename Enable=void > struct expected_count { static const int value{0};};template< typename T >struct expected_count< T, typename std::enable_if<!is_mutable_container< T >::value &&!is_wrapper< T >::value && !std::is_void< T >::value >::type > { static constexpr int value{1};};template< typename T > struct expected_count< T, typename std::enable_if< is_mutable_container< T >::value >::type > { static constexpr int value{expected_max_vector_size};};template< typename T >struct expected_count< T, typename std::enable_if<!is_mutable_container< T >::value &&is_wrapper< T >::value >::type > { static constexpr int value{expected_count< typename T::value_type >::value};};enum class object_category :int { char_value=1, integral_value=2, unsigned_integral=4, enumeration=6, boolean_value=8, floating_point=10, number_constructible=12, double_constructible=14, integer_constructible=16, string_assignable=23, string_constructible=24, other=45, wrapper_value=50, complex_number=60, tuple_value=70, container_value=80,};template< typename T, typename Enable=void > struct classify_object { static constexpr object_category value{object_category::other};};template< typename T >struct classify_object< T, typename std::enable_if< std::is_integral< T >::value &&!std::is_same< T, char >::value &&std::is_signed< T >::value && !is_bool< T >::value &&!std::is_enum< T >::value >::type > { static constexpr object_category value{object_category::integral_value};};template< typename T >struct classify_object< T, typename std::enable_if< std::is_integral< T >::value &&std::is_unsigned< T >::value && !std::is_same< T, char >::value &&!is_bool< T >::value >::type > { static constexpr object_category value{object_category::unsigned_integral};};template< typename T >struct classify_object< T, typename std::enable_if< std::is_same< T, char >::value &&!std::is_enum< T >::value >::type > { static constexpr object_category value{object_category::char_value};};template< typename T > struct classify_object< T, typename std::enable_if< is_bool< T >::value >::type > { static constexpr object_category value{object_category::boolean_value};};template< typename T > struct classify_object< T, typename std::enable_if< std::is_floating_point< T >::value >::type > { static constexpr object_category value{object_category::floating_point};};template< typename T >struct classify_object< T, typename std::enable_if<!std::is_floating_point< T >::value &&!std::is_integral< T >::value && std::is_assignable< T &, std::string >::value >::type > { static constexpr object_category value{object_category::string_assignable};};template< typename T >struct classify_object< T, typename std::enable_if<!std::is_floating_point< T >::value &&!std::is_integral< T >::value && !std::is_assignable< T &, std::string >::value &&(type_count< T >::value==1) && std::is_constructible< T, std::string >::value >::type > { static constexpr object_category value{object_category::string_constructible};};template< typename T > struct classify_object< T, typename std::enable_if< std::is_enum< T >::value >::type > { static constexpr object_category value{object_category::enumeration};};template< typename T > struct classify_object< T, typename std::enable_if< is_complex< T >::value >::type > { static constexpr object_category value{object_category::complex_number};};template< typename T > struct uncommon_type { using type=typename std::conditional<!std::is_floating_point< T >::value &&!std::is_integral< T >::value && !std::is_assignable< T &, std::string >::value && !std::is_constructible< T, std::string >::value &&!is_complex< T >::value && !is_mutable_container< T >::value &&!std::is_enum< T >::value, std::true_type, std::false_type >::type; static constexpr bool value=type::value;};template< typename T >struct classify_object< T, typename std::enable_if<(!is_mutable_container< T >::value &&is_wrapper< T >::value && !is_tuple_like< T >::value &&uncommon_type< T >::value)>::type > { static constexpr object_category value{object_category::wrapper_value};};template< typename T >struct classify_object< T, typename std::enable_if< uncommon_type< T >::value &&type_count< T >::value==1 && !is_wrapper< T >::value &&is_direct_constructible< T, double >::value && is_direct_constructible< T, int >::value >::type > { static constexpr object_category value{object_category::number_constructible};};template< typename T >struct classify_object< T, typename std::enable_if< uncommon_type< T >::value &&type_count< T >::value==1 && !is_wrapper< T >::value &&!is_direct_constructible< T, double >::value && is_direct_constructible< T, int >::value >::type > { static constexpr object_category value{object_category::integer_constructible};};template< typename T >struct classify_object< T, typename std::enable_if< uncommon_type< T >::value &&type_count< T >::value==1 && !is_wrapper< T >::value &&is_direct_constructible< T, double >::value && !is_direct_constructible< T, int >::value >::type > { static constexpr object_category value{object_category::double_constructible};};template< typename T >struct classify_object< T, typename std::enable_if< is_tuple_like< T >::value &&((type_count< T >::value >=2 &&!is_wrapper< T >::value)||(uncommon_type< T >::value &&!is_direct_constructible< T, double >::value && !is_direct_constructible< T, int >::value))>::type > { static constexpr object_category value{object_category::tuple_value}; };template< typename T > struct classify_object< T, typename std::enable_if< is_mutable_container< T >::value >::type > { static constexpr object_category value{object_category::container_value};};template< typename T, enable_if_t< classify_object< T >::value==object_category::char_value, detail::enabler >=detail::dummy >constexpr const char *type_name() { return "CHAR";}template< typename T, enable_if_t< classify_object< T >::value==object_category::integral_value|| classify_object< T >::value==object_category::integer_constructible, detail::enabler >=detail::dummy >constexpr const char *type_name() { return "INT";}template< typename T, enable_if_t< classify_object< T >::value==object_category::unsigned_integral, detail::enabler >=detail::dummy >constexpr const char *type_name() { return "UINT";}template< typename T, enable_if_t< classify_object< T >::value==object_category::floating_point|| classify_object< T >::value==object_category::number_constructible|| classify_object< T >::value==object_category::double_constructible, detail::enabler >=detail::dummy >constexpr const char *type_name() { return "FLOAT";}template< typename T, enable_if_t< classify_object< T >::value==object_category::enumeration, detail::enabler >=detail::dummy >constexpr const char *type_name() { return "ENUM";}template< typename T, enable_if_t< classify_object< T >::value==object_category::boolean_value, detail::enabler >=detail::dummy >constexpr const char *type_name() { return "BOOLEAN";}template< typename T, enable_if_t< classify_object< T >::value==object_category::complex_number, detail::enabler >=detail::dummy >constexpr const char *type_name() { return "COMPLEX";}template< typename T, enable_if_t< classify_object< T >::value >=object_category::string_assignable && classify_object< T >::value<=object_category::other, detail::enabler >=detail::dummy >constexpr const char *type_name() { return "TEXT";}template< typename T, enable_if_t< classify_object< T >::value==object_category::tuple_value &&type_count_base< T >::value >=2, detail::enabler >=detail::dummy >std::string type_name(); template< typename T, enable_if_t< classify_object< T >::value==object_category::container_value|| classify_object< T >::value==object_category::wrapper_value, detail::enabler >=detail::dummy >std::string type_name(); template< typename T, enable_if_t< classify_object< T >::value==object_category::tuple_value &&type_count_base< T >::value==1, detail::enabler >=detail::dummy >inline std::string type_name() { return type_name< typename std::decay< typename std::tuple_element< 0, T >::type >::type >();}template< typename T, std::size_t I >inline typename std::enable_if< I==type_count_base< T >::value, std::string >::type tuple_name() { return std::string{};}template< typename T, std::size_t I >inline typename std::enable_if<(I< type_count_base< T >::value), std::string >::type tuple_name() { std::string str=std::string(type_name< typename std::decay< typename std::tuple_element< I, T >::type >::type >())+ ','+tuple_name< T, I+1 >(); if(str.back()==',') str.pop_back(); return str;}template< typename T, enable_if_t< classify_object< T >::value==object_category::tuple_value &&type_count_base< T >::value >=2, detail::enabler > >inline std::string type_name() { auto tname=std::string(1, '[')+tuple_name< T, 0 >(); tname.push_back(']'); return tname;}template< typename T, enable_if_t< classify_object< T >::value==object_category::container_value|| classify_object< T >::value==object_category::wrapper_value, detail::enabler > >inline std::string type_name() { return type_name< typename T::value_type >();}template< typename T, enable_if_t< std::is_unsigned< T >::value, detail::enabler >=detail::dummy >bool integral_conversion(const std::string &input, T &output) noexcept { if(input.empty()) { return false; } char *val=nullptr; std::uint64_t output_ll=std::strtoull(input.c_str(), &val, 0); output=static_cast< T >(output_ll); if(val==(input.c_str()+input.size()) &&static_cast< std::uint64_t >(output)==output_ll) { return true; } val=nullptr; std::int64_t output_sll=std::strtoll(input.c_str(), &val, 0); if(val==(input.c_str()+input.size())) { output=(output_sll< 0) ? static_cast< T >(0) CLI::detail::return ( static_cast< std::int64_t > output = =output_sll)
constexpr

Recursively generate the tuple type name.

◆ rjoin()

template<typename T >
std::string CLI::detail::rjoin ( const T & v,
std::string delim = "," )

Join a string in reverse order.

◆ rtrim() [1/2]

std::string & CLI::detail::rtrim ( std::string & str)
inline

Trim whitespace from right of string.

◆ rtrim() [2/2]

std::string & CLI::detail::rtrim ( std::string & str,
const std::string & filter )
inline

Trim anything from right of string.

◆ search() [1/2]

template<typename T , typename V , enable_if_t<!has_find< T, V >::value, detail::enabler > = detail::dummy>
auto CLI::detail::search ( const T & set,
const V & val ) -> std::pair<bool, decltype(std::begin(detail::smart_deref(set)))>

A search function.

A search function that uses the built in find function.

◆ search() [2/2]

template<typename T , typename V >
auto CLI::detail::search ( const T & set,
const V & val,
const std::function< V(V)> & filter_function ) -> std::pair<bool, decltype(std::begin(detail::smart_deref(set)))>

A search function with a filter function.

◆ smart_deref() [1/2]

template<typename T , enable_if_t<!is_copyable_ptr< typename std::remove_reference< T >::type >::value, detail::enabler > = detail::dummy>
std::remove_reference< T >::type & CLI::detail::smart_deref ( T & value)

◆ smart_deref() [2/2]

template<typename T , enable_if_t< is_copyable_ptr< typename std::remove_reference< T >::type >::value, detail::enabler > = detail::dummy>
auto CLI::detail::smart_deref ( T value) -> decltype(*value)

◆ split()

std::vector< std::string > CLI::detail::split ( const std::string & s,
char delim )
inline

Split a string by a delim.

◆ split_long()

bool CLI::detail::split_long ( const std::string & current,
std::string & name,
std::string & value )
inline

◆ split_names()

std::vector< std::string > CLI::detail::split_names ( std::string current)
inline

◆ split_program_name()

std::pair< std::string, std::string > CLI::detail::split_program_name ( std::string commandline)
inline

Split a string into a program name and command line arguments the string is assumed to contain a file name followed by other arguments the return value contains is a pair with the first argument containing the program name and the second everything else.

◆ split_short()

bool CLI::detail::split_short ( const std::string & current,
std::string & name,
std::string & rest )
inline

◆ split_windows_style()

bool CLI::detail::split_windows_style ( const std::string & current,
std::string & name,
std::string & value )
inline

◆ to_flag_value()

std::int64_t CLI::detail::to_flag_value ( std::string val)
inline

Convert a flag into an integer value typically binary flags.

◆ to_lower()

std::string CLI::detail::to_lower ( std::string str)
inline

Return a lower case version of a string.

◆ to_string() [1/3]

template<typename T , enable_if_t< std::is_constructible< std::string, T >::value &&!std::is_convertible< T, std::string >::value, detail::enabler > = detail::dummy>
std::string CLI::detail::to_string ( const T & value)

Construct a string from the object.

◆ to_string() [2/3]

template<typename T , enable_if_t<!std::is_convertible< std::string, T >::value &&!std::is_constructible< std::string, T >::value &&is_ostreamable< T >::value, detail::enabler > = detail::dummy>
std::string CLI::detail::to_string ( T && value)

Convert an object to a string (streaming must be supported for that type)

convert a readable container to a string

If conversion is not supported, return an empty string (streaming is not supported for that type)

◆ to_string() [3/3]

template<typename T , enable_if_t< std::is_convertible< T, std::string >::value, detail::enabler > = detail::dummy>
auto CLI::detail::to_string ( T && value) -> decltype(std::forward<T>(value))

Convert an object to a string (directly forward if this can become a string)

◆ trim() [1/3]

std::string & CLI::detail::trim ( std::string & str)
inline

Trim whitespace from string.

◆ trim() [2/3]

std::string & CLI::detail::trim ( std::string & str,
const std::string filter )
inline

Trim anything from string.

◆ trim() [3/3]

CLI::detail::trim ( str )

◆ trim_copy() [1/2]

std::string CLI::detail::trim_copy ( const std::string & str)
inline

Make a copy of the string and then trim it.

◆ trim_copy() [2/2]

std::string CLI::detail::trim_copy ( const std::string & str,
const std::string & filter )
inline

Make a copy of the string and then trim it, any filter string can be used (any char in string is filtered)

◆ tuple_type_size()

template<typename T , std::size_t I>
std::enable_if< I==type_count_base< T >::value, int >::type CLI::detail::tuple_type_size ( )
constexpr

0 if the index > tuple size

◆ valid_alias_name_string()

bool CLI::detail::valid_alias_name_string ( const std::string & str)
inline

Verify an app name.

◆ valid_first_char()

template<typename T >
bool CLI::detail::valid_first_char ( T c)

Verify the first character of an option

  • is a trigger character, ! has special meaning and new lines would just be annoying to deal with

◆ valid_later_char()

template<typename T >
bool CLI::detail::valid_later_char ( T c)

Verify following characters of an option.

◆ valid_name_string()

bool CLI::detail::valid_name_string ( const std::string & str)
inline

Verify an option/subcommand name.

◆ value_string() [1/2]

template<typename T , enable_if_t< std::is_arithmetic< T >::value, detail::enabler > = detail::dummy>
std::string CLI::detail::value_string ( const T & value)

get a string as a convertible value for arithmetic types

get a string as a convertible value for enumerations

◆ value_string() [2/2]

template<typename T , enable_if_t<!std::is_enum< T >::value &&!std::is_arithmetic< T >::value, detail::enabler > = detail::dummy>
auto CLI::detail::value_string ( const T & value) -> decltype(to_string(value))

for other types just use the regular to_string function

◆ while()

CLI::detail::while ( !str. empty())

Variable Documentation

◆ dummy

enabler CLI::detail::dummy = {}
constexpr

An instance to use in EnableIf.

◆ embeddedQuote

bool CLI::detail::embeddedQuote = false

◆ expected_max_vector_size

int CLI::detail::expected_max_vector_size {1 << 29}
constexpr

a constant defining an expected max vector size defined to be a big number that could be multiplied by 4 and not produce overflow for some expected uses

◆ false

return CLI::detail::false

◆ find_ws

auto CLI::detail::find_ws
Initial value:
= [delimiter](char ch) {
return (delimiter == '\0') ? (std::isspace<char>(ch, std::locale()) != 0) : (ch == delimiter);
}

Split a string '"one two" "three"' into 'one two', 'three' Quote characters can be ‘ ’ or " inline std::vector<std::string> split_up(std::string str, char delimiter = '\0') { @iverbatim const std::string delims("\'"`");

◆ keyChar

char CLI::detail::keyChar = ' '

◆ output

return CLI::detail::output