libcopp  2.2.0
cmd_option.h
Go to the documentation of this file.
1 #ifndef UTIL_CLI_CMDOPTION_H
2 #define UTIL_CLI_CMDOPTION_H
3 
4 #pragma once
5 
22 #include <assert.h>
23 #include <cstdio>
24 #include <exception>
25 #include <set>
26 
27 #include <map>
28 #include <memory>
29 #include <ostream>
30 #include <sstream>
31 #include <vector>
32 
33 #include "std/ref.h"
34 
35 // 载入绑定器
36 #include "cli/cmd_option_bind.h"
38 #include "cli/cmd_option_string.h"
39 #include "cmd_option_list.h"
40 
41 #include "shell_font.h"
42 
43 namespace util {
44 namespace cli {
45 // 标准指令处理函数(无返回值,参数为选项的映射表)
46 // void function_name (cmd_option_list&, [参数]); // 函数参数可选
47 // void function_name (callback_param, [参数]); // 函数参数可选
48 
49 // 值类型
50 typedef std::shared_ptr<cli::cmd_option_value> value_type;
51 
65 template <typename TCmdStr>
67  public:
68  typedef unsigned char uc_t;
72  typedef std::shared_ptr<binder::cmd_option_bind_base> func_ptr_t;
73  typedef std::map<TCmdStr, func_ptr_t> funmap_type;
74 
75  protected:
76  static short map_value_[256]; // 记录不同字符的映射关系
77  static char trans_value_[256]; // 记录特殊转义字符
78 
79  funmap_type callback_funcs_; // 记录命令的映射函数
80  funmap_type callback_children_; // 子命令组额外索引
83 
89  void run_cmd(const TCmdStr &cmd_content, callback_param params) const {
90  typename funmap_type::const_iterator iter = callback_funcs_.find(cmd_content);
91 
92  // 如果是顶层调用则添加根指令调用栈
93  if (params.get_cmd_array().empty()) {
94  params.append_cmd(ROOT_NODE_CMD, std::const_pointer_cast<binder::cmd_option_bind_base>(shared_from_this()));
95  }
96 
97  if (iter == callback_funcs_.end()) {
98  // 内定命令不报“找不到指令”错
99  if (cmd_content == "@OnDefault") return;
100 
101  iter = callback_funcs_.find("@OnError"); // 查找错误处理函数
102  if (iter != callback_funcs_.end()) {
103  // 错误附加内容(错误内容)
104  params.add("@ErrorMsg=Command Invalid");
105  params.append_cmd(cmd_content.c_str(), iter->second); // 添加当前指令调用栈
106 
107  (*iter->second)(params);
108  }
109  return;
110  }
111 
112  // 添加当前指令调用栈
113  params.append_cmd(cmd_content.c_str(), iter->second);
114  (*iter->second)(params);
115  }
116 
121  std::cout << "Help:" << std::endl;
122  std::cout << (*this);
123  }
124 
125  public:
126  void list_help_msg(help_list_t &msg, const std::string &prefix) const {
127  for (typename funmap_type::const_iterator iter = callback_funcs_.begin(); iter != callback_funcs_.end(); ++iter) {
128  if (iter->first.empty() || '@' == iter->first[0]) {
129  continue;
130  }
131 
132  help_list_t::iterator iter_m;
133  help_msg_t *obj;
134  for (iter_m = msg.begin(), obj = nullptr; iter_m != msg.end(); ++iter_m) {
135  if ((*iter_m).binded_obj == iter->second) {
136  obj = &(*iter_m);
137  break;
138  }
139  }
140 
141  // all children do not make a help_msg_t
142  if (callback_children_.find(iter->first) != callback_children_.end()) {
143 #if defined(LIBCOPP_MACRO_ENABLE_RTTI) && LIBCOPP_MACRO_ENABLE_RTTI
144  self_type *child = dynamic_cast<self_type *>(iter->second.get());
145 #else
146  self_type *child = static_cast<self_type *>(iter->second.get());
147 #endif
148  assert(child);
149  child->list_help_msg(msg, (prefix + " ") + iter->first.c_str());
150  continue;
151  }
152 
153  if (nullptr == obj) {
154  msg.push_back(help_msg_t());
155  obj = &msg.back();
156  assert(obj);
157  obj->binded_obj = iter->second;
158  obj->description = iter->second->get_help_msg();
159  }
160 
161  // any string to std::string
162  std::string full_cmd;
163  full_cmd.reserve(prefix.capacity() + iter->first.capacity());
164  if (!prefix.empty()) {
165  full_cmd = prefix;
166  full_cmd += " ";
167  }
168  full_cmd += iter->first.c_str();
169  obj->cmd_paths.push_back(full_cmd);
170  }
171  }
172 
173  static std::ostream &dump(std::ostream &os, const self_type &self, const std::string &prefix) {
174  help_list_t msgs;
175  self.list_help_msg(msgs, "");
176 
177  size_t cmd_padding = 4;
178  // sort all commands of the same callback
179  for (help_list_t::iterator iter = msgs.begin(); iter != msgs.end(); ++iter) {
180  std::sort((*iter).cmd_paths.begin(), (*iter).cmd_paths.end());
181  std::stringstream ss;
182  bool not_first = false;
183  for (std::vector<std::string>::iterator cmd_it = (*iter).cmd_paths.begin(); cmd_it != (*iter).cmd_paths.end();
184  ++cmd_it) {
185  if (not_first) {
186  ss << ", ";
187  }
188  ss << *cmd_it;
189  not_first = true;
190  }
191 
192  (*iter).all_cmds = ss.str();
193  if ((*iter).all_cmds.size() >= cmd_padding) {
194  cmd_padding = (((*iter).all_cmds.size() >> 2) + 1) << 2;
195  }
196  }
197 
198  std::sort(msgs.begin(), msgs.end(), binder::cmd_option_bind_base::sort_by_all_cmds);
199 
200  for (help_list_t::iterator iter = msgs.begin(); iter != msgs.end(); ++iter) {
201  shell_stream ss(os);
202 
203  ss().open(self.help_cmd_style_) << prefix << (*iter).all_cmds;
204  if ((*iter).all_cmds.size() < cmd_padding) {
205  std::string padding_space;
206  padding_space.resize(cmd_padding - (*iter).all_cmds.size(), ' ');
207  ss() << padding_space;
208  }
209  ss().open(self.help_description_style_) << (*iter).description << std::endl;
210  }
211 
212  return os;
213  }
214 
215  friend std::ostream &operator<<(std::ostream &os, const self_type &self) { return dump(os, self, std::string()); }
216 
217  std::ostream &dump(std::ostream &os, const std::string &prefix) { return dump(os, *this, prefix); }
218 
225  static const char *get_segment(const char *begin_str, std::string &val) {
226  val.clear();
227  char flag; // 字符串开闭字符
228 
229  // 去除分隔符前缀
230  while (*begin_str && (map_value_[(uc_t)*begin_str] & SPLITCHAR)) ++begin_str;
231 
232  while (*begin_str && !(map_value_[(uc_t)*begin_str] & SPLITCHAR)) {
233  if (!(map_value_[(uc_t)*begin_str] & STRINGSYM)) {
234  val += *begin_str;
235  ++begin_str;
236  } else {
237  flag = *begin_str;
238  ++begin_str;
239 
240  while (*begin_str && *begin_str != flag) {
241  char cur_byte = *begin_str;
242  if (map_value_[(uc_t)*begin_str] & TRANSLATE) {
243  if (*(begin_str + 1)) {
244  ++begin_str;
245  cur_byte = trans_value_[(uc_t)*begin_str];
246  }
247  }
248 
249  val += cur_byte;
250  ++begin_str;
251  }
252 
253  ++begin_str;
254  break; // 字符串结束后参数结束
255  }
256  }
257 
258  // 去除分隔符后缀
259  while (*begin_str && (map_value_[(uc_t)*begin_str] & SPLITCHAR)) ++begin_str;
260  return begin_str;
261  }
262 
268  static std::vector<std::string> split_cmd(const char *begin_str) {
269  std::vector<std::string> ret;
270  for (const char *begin_ptr = begin_str; (*begin_ptr);) {
271  std::string cmd_content;
272  // 去除命令分隔符前缀
273  while ((*begin_ptr) && (map_value_[(uc_t)*begin_ptr] & CMDSPLIT)) ++begin_ptr;
274 
275  // 分离命令
276  while ((*begin_ptr) && !(map_value_[(uc_t)*begin_ptr] & CMDSPLIT)) {
277  cmd_content.push_back(*begin_ptr);
278  ++begin_ptr;
279  }
280 
281  if (cmd_content.size() > 0) ret.push_back(cmd_content);
282  }
283 
284  return ret;
285  }
286 
287  private:
292  : help_cmd_style_(shell_font_style::SHELL_FONT_COLOR_YELLOW |
293  static_cast<int>(shell_font_style::SHELL_FONT_SPEC_BOLD)),
295  // 如果已初始化则跳过
296  if (map_value_[(uc_t)' '] & SPLITCHAR) return;
297 
298  // 分隔符
299  map_value_[(uc_t)' '] = map_value_[(uc_t)'\t'] = map_value_[(uc_t)'\r'] = map_value_[(uc_t)'\n'] = SPLITCHAR;
300  // 字符串开闭符
301  map_value_[(uc_t)'\''] = map_value_[(uc_t)'\"'] = STRINGSYM;
302  // 转义标记符
303  map_value_[(uc_t)'\\'] = TRANSLATE;
304  // 指令分隔符
305  map_value_[(uc_t)' '] |= CMDSPLIT;
306  map_value_[(uc_t)','] = map_value_[(uc_t)';'] = CMDSPLIT;
307 
308  // 转义字符设置
309  for (int i = 0; i < 256; ++i) trans_value_[i] = (uc_t)i;
310 
311  trans_value_[(uc_t)'0'] = '\0';
312  trans_value_[(uc_t)'a'] = '\a';
313  trans_value_[(uc_t)'b'] = '\b';
314  trans_value_[(uc_t)'f'] = '\f';
315  trans_value_[(uc_t)'r'] = '\r';
316  trans_value_[(uc_t)'n'] = '\n';
317  trans_value_[(uc_t)'t'] = '\t';
318  trans_value_[(uc_t)'v'] = '\v';
319  trans_value_[(uc_t)'\\'] = '\\';
320  trans_value_[(uc_t)'\''] = '\'';
321  trans_value_[(uc_t)'\"'] = '\"';
322  }
323 
324  public:
325  typedef std::shared_ptr<cmd_option_bind> ptr_type;
326  static ptr_type create() { return ptr_type(new cmd_option_bind()); }
327 
332  std::shared_ptr<std::vector<const char *> > get_cmd_names() const {
333  typename funmap_type::const_iterator iter = callback_funcs_.begin();
334  std::shared_ptr<std::vector<const char *> > ret_ptr =
335  std::shared_ptr<std::vector<const char *> >(new std::vector<const char *>());
336  while (iter != callback_funcs_.end()) {
337  ret_ptr->push_back(iter->first.c_str());
338  ++iter;
339  }
340  return ret_ptr;
341  }
342 
348  std::shared_ptr<binder::cmd_option_bind_base> get_binded_cmd(const char *cmd_name) const {
349  typename funmap_type::const_iterator iter = callback_funcs_.find(cmd_name);
350  if (iter == callback_funcs_.end()) return std::shared_ptr<binder::cmd_option_bind_base>();
351  return iter->second;
352  }
353 
354  size_t size() const { return callback_funcs_.size(); }
355  size_t empty() const { return callback_funcs_.empty(); }
356  const funmap_type &get_all() const { return callback_funcs_; }
357 
358  size_t children_size() const { return callback_children_.size(); }
359  size_t children_empty() const { return callback_children_.empty(); }
361 
362  int get_help_cmd_style() const { return help_cmd_style_; }
363  void set_help_cmd_style(int style) { help_cmd_style_ = style; }
366 
381  void start(callback_param args, bool is_single_cmd = false) const {
382  int argv = static_cast<int>(args.get_params_number());
383  cmd_option_list cmd_args;
384  TCmdStr cmd_content = is_single_cmd ? "@OnError" : "@OnDefault";
385  for (int i = -1; i < argv;) {
386  ++i;
387  cmd_args.clear();
388  cmd_args.load_cmd_array(args.get_cmd_array());
389  cmd_args.set_ext_param(args.get_ext_param());
390 
391  for (; i < argv; ++i) {
392  // 把所有的非指令字符串设为指令参数
393  if (callback_funcs_.find(args[i]->to_string()) == callback_funcs_.end()) {
394  cmd_args.add(args[i]->to_string());
395  } else {
396  // 如果是单指令且有未知参数则分发@OnError错误处理
397  if (is_single_cmd && cmd_args.get_params_number() > 0) {
398  run_cmd(cmd_content, cmd_args);
399  cmd_args.clear();
400  cmd_args.load_cmd_array(args.get_cmd_array());
401  cmd_args.set_ext_param(args.get_ext_param());
402  }
403 
404  // 追加所有参数,执行单指令
405  if (is_single_cmd) {
406  cmd_content = TCmdStr(args[i]->to_cpp_string().c_str(), args[i]->to_cpp_string().size());
407  for (++i; i < argv; ++i) cmd_args.add(args[i]->to_string());
408  }
409  break;
410  }
411  }
412 
413  run_cmd(cmd_content, cmd_args);
414  if (i >= argv) break;
415  cmd_content = TCmdStr(args[i]->to_cpp_string().c_str(), args[i]->to_cpp_string().size());
416  }
417  }
418 
426  inline void start(int argv, const char *argc[], bool is_single_cmd = false, void *ext_param = nullptr) const {
427  cmd_option_list copt_list(argv, argc);
428  copt_list.set_ext_param(ext_param);
429 
430  start(copt_list, is_single_cmd);
431  }
432 
440  inline void start(int argv, char *argc[], bool is_single_cmd = false, void *ext_param = nullptr) const {
441  typedef const char *conv_char_t;
442 
443  start(argv, const_cast<conv_char_t *>(argc), is_single_cmd, ext_param);
444  }
445 
452  inline void start(const std::vector<std::string> &cmds, bool is_single_cmd = false, void *ext_param = nullptr) const {
453  cmd_option_list copt_list(cmds);
454  copt_list.set_ext_param(ext_param);
455 
456  start(copt_list, is_single_cmd);
457  }
458 
464  void start(const char *cmd_content, bool is_single_cmd = false, void *ext_param = nullptr) const {
465  cmd_option_list cmds;
466  std::string seg;
467 
468  // 分离指令
469  while (*cmd_content) {
470  cmd_content = get_segment(cmd_content, seg);
471  cmds.add(seg.c_str());
472  }
473 
474  cmds.set_ext_param(ext_param);
475 
476  start(cmds, is_single_cmd);
477  }
478 
484  inline void start(const std::string &cmd_content, bool is_single_cmd = false, void *ext_param = nullptr) const {
485  start(cmd_content.c_str(), is_single_cmd, ext_param);
486  }
487 
492  inline void unbind_cmd(const std::string &cmd_content) {
493  TCmdStr cmd_obj = TCmdStr(cmd_content.c_str(), cmd_content.size());
494  callback_funcs_.erase(cmd_obj);
495  callback_children_.erase(cmd_content);
496  }
497 
501  inline void unbind_all_cmd() {
502  callback_funcs_.clear();
503  callback_children_.clear();
504  }
505 
510  inline std::shared_ptr<binder::cmd_option_bindt<
513  bind_help_cmd(const char *help_cmd_content) {
514  return bind_cmd(help_cmd_content, &cmd_option_bind<TCmdStr>::on_help, this);
515  }
516 
520  virtual void operator()(callback_param arg) {
521  // 响应@OnCallFunc事件
522  typename funmap_type::const_iterator iter = callback_funcs_.find("@OnCallFunc");
523  if (iter != callback_funcs_.end()) (*iter->second)(arg);
524 
525  // 重新执行指令集, 进入子结构的一定是单指令
526  start(arg, true);
527  }
528 
533  virtual std::string get_help_msg(const char *prefix_data = "") const {
534  std::set<typename funmap_type::mapped_type> set_obj;
535  std::string help_msg_content;
536 
537  for (typename funmap_type::const_iterator iter = callback_funcs_.begin(); iter != callback_funcs_.end(); ++iter) {
538  // 删除重复的引用对象
539  if (set_obj.find(iter->second) != set_obj.end()) continue;
540 
541  // 跳过内置命令
542  if ('@' == *iter->first.c_str()) continue;
543 
544  set_obj.insert(iter->second);
545  std::string cmd_help = iter->second->get_help_msg((prefix_data + help_msg_).c_str());
546 
547  if (cmd_help.size() > 0) {
548  if (help_msg_content.size() > 0 && '\n' != *help_msg_content.rbegin()) help_msg_content += "\r\n";
549  help_msg_content += cmd_help;
550  }
551  }
552  return help_msg_content;
553  }
554 
572  template <typename _F,
573  typename... _Args> // 绑定函数(_Arg:参数[注意值的复制发生在本函数执行时], _R: 绑定函数返回值类型)
574  std::shared_ptr<binder::cmd_option_bindt<typename binder::maybe_wrap_member_pointer<_F>::caller_type,
576  bind_cmd(const std::string &cmd_content, _F raw_fn, _Args... args) {
577  typedef binder::cmd_option_bind_param_list<_Args...> list_type;
578  typedef typename binder::maybe_wrap_member_pointer<_F>::caller_type caller_type;
579  typedef std::shared_ptr<binder::cmd_option_bindt<caller_type, list_type> > obj_type;
580 
581  obj_type fn =
582  obj_type(new binder::cmd_option_bindt<caller_type, list_type>(caller_type(raw_fn), list_type(args...)));
583 
584  std::vector<std::string> cmds = split_cmd(cmd_content.c_str());
585  for (std::vector<std::string>::size_type index = 0; index < cmds.size(); ++index) {
586  TCmdStr cmd_obj = TCmdStr(cmds[index].c_str(), cmds[index].size());
587  callback_funcs_[cmd_obj] = fn;
588  }
589 
590  return fn;
591  }
592 
601  std::shared_ptr<binder::cmd_option_bind_base> bind_child_cmd(
602  const std::string cmd_content, std::shared_ptr<binder::cmd_option_bind_base> base_node) {
603  std::vector<std::string> cmds = split_cmd(cmd_content.c_str());
604  for (std::vector<std::string>::size_type index = 0; index < cmds.size(); ++index) {
605  TCmdStr cmd_obj = TCmdStr(cmds[index].c_str(), cmds[index].size());
606  callback_funcs_[cmd_obj] = base_node;
607  callback_children_[cmd_obj] = base_node;
608  }
609 
610  return base_node;
611  }
612 
613  std::shared_ptr<binder::cmd_option_bind_base> bind_child_cmd(const std::string cmd_content, ptr_type cmd_opt) {
614 #if defined(LIBATFRAME_UTILS_ENABLE_RTTI) && LIBATFRAME_UTILS_ENABLE_RTTI
615  std::shared_ptr<binder::cmd_option_bind_base> base_node =
616  std::dynamic_pointer_cast<binder::cmd_option_bind_base>(cmd_opt);
617 #else
618  std::shared_ptr<binder::cmd_option_bind_base> base_node =
619  std::static_pointer_cast<binder::cmd_option_bind_base>(cmd_opt);
620 #endif
621  std::vector<std::string> cmds = split_cmd(cmd_content.c_str());
622  for (std::vector<std::string>::size_type index = 0; index < cmds.size(); ++index) {
623  TCmdStr cmd_obj = TCmdStr(cmds[index].c_str(), cmds[index].size());
624  callback_funcs_[cmd_obj] = base_node;
625  callback_children_[cmd_obj] = base_node;
626  }
627 
628  return base_node;
629  }
630 };
631 
632 template <typename Ty>
633 short cmd_option_bind<Ty>::map_value_[256] = {0};
634 
635 template <typename Ty>
636 char cmd_option_bind<Ty>::trans_value_[256] = {0};
637 
638 // 类型重定义
641 } // namespace cli
642 } // namespace util
643 #endif /* CMDOPTION_H_ */
std::vector< help_msg_t > help_list_t
static bool sort_by_all_cmds(const help_msg_t &l, const help_msg_t &r)
const funmap_type & get_all_children() const
Definition: cmd_option.h:360
std::shared_ptr< binder::cmd_option_bind_base > bind_child_cmd(const std::string cmd_content, ptr_type cmd_opt)
Definition: cmd_option.h:613
static std::vector< std::string > split_cmd(const char *begin_str)
Definition: cmd_option.h:268
friend std::ostream & operator<<(std::ostream &os, const self_type &self)
Definition: cmd_option.h:215
size_t children_size() const
Definition: cmd_option.h:358
cmd_option_bind< TCmdStr > self_type
Definition: cmd_option.h:69
void start(const std::vector< std::string > &cmds, bool is_single_cmd=false, void *ext_param=nullptr) const
Definition: cmd_option.h:452
void set_help_cmd_style(int style)
Definition: cmd_option.h:363
funmap_type callback_funcs_
Definition: cmd_option.h:79
std::shared_ptr< cmd_option_bind > ptr_type
Definition: cmd_option.h:325
static std::ostream & dump(std::ostream &os, const self_type &self, const std::string &prefix)
Definition: cmd_option.h:173
void on_help(callback_param)
Definition: cmd_option.h:120
void run_cmd(const TCmdStr &cmd_content, callback_param params) const
Definition: cmd_option.h:89
void start(const char *cmd_content, bool is_single_cmd=false, void *ext_param=nullptr) const
Definition: cmd_option.h:464
void list_help_msg(help_list_t &msg, const std::string &prefix) const
Definition: cmd_option.h:126
size_t children_empty() const
Definition: cmd_option.h:359
virtual std::string get_help_msg(const char *prefix_data="") const
Definition: cmd_option.h:533
binder::cmd_option_bind_base::help_list_t help_list_t
Definition: cmd_option.h:71
std::ostream & dump(std::ostream &os, const std::string &prefix)
Definition: cmd_option.h:217
binder::cmd_option_bind_base::help_msg_t help_msg_t
Definition: cmd_option.h:70
std::shared_ptr< binder::cmd_option_bindt< typename binder::maybe_wrap_member_pointer< _F >::caller_type, binder::cmd_option_bind_param_list< _Args... > > > bind_cmd(const std::string &cmd_content, _F raw_fn, _Args... args)
Definition: cmd_option.h:576
static short map_value_[256]
Definition: cmd_option.h:76
void start(int argv, const char *argc[], bool is_single_cmd=false, void *ext_param=nullptr) const
Definition: cmd_option.h:426
std::shared_ptr< binder::cmd_option_bind_base > func_ptr_t
Definition: cmd_option.h:72
virtual void operator()(callback_param arg)
Definition: cmd_option.h:520
std::map< TCmdStr, func_ptr_t > funmap_type
Definition: cmd_option.h:73
void start(const std::string &cmd_content, bool is_single_cmd=false, void *ext_param=nullptr) const
Definition: cmd_option.h:484
std::shared_ptr< binder::cmd_option_bind_base > get_binded_cmd(const char *cmd_name) const
Definition: cmd_option.h:348
void start(callback_param args, bool is_single_cmd=false) const
Definition: cmd_option.h:381
static char trans_value_[256]
Definition: cmd_option.h:77
int get_help_description_style() const
Definition: cmd_option.h:364
void unbind_cmd(const std::string &cmd_content)
Definition: cmd_option.h:492
funmap_type callback_children_
Definition: cmd_option.h:80
int get_help_cmd_style() const
Definition: cmd_option.h:362
static ptr_type create()
Definition: cmd_option.h:326
static const char * get_segment(const char *begin_str, std::string &val)
Definition: cmd_option.h:225
const funmap_type & get_all() const
Definition: cmd_option.h:356
std::shared_ptr< binder::cmd_option_bind_base > bind_child_cmd(const std::string cmd_content, std::shared_ptr< binder::cmd_option_bind_base > base_node)
Definition: cmd_option.h:601
void set_help_description_style(int style)
Definition: cmd_option.h:365
void start(int argv, char *argc[], bool is_single_cmd=false, void *ext_param=nullptr) const
Definition: cmd_option.h:440
std::shared_ptr< binder::cmd_option_bindt< typename binder::maybe_wrap_member_pointer< void(cmd_option_bind< TCmdStr >::*)(callback_param)>::caller_type, binder::cmd_option_bind_param_list< cmd_option_bind< TCmdStr > * > > > bind_help_cmd(const char *help_cmd_content)
Definition: cmd_option.h:513
std::shared_ptr< std::vector< const char * > > get_cmd_names() const
Definition: cmd_option.h:332
void append_cmd(const char *cmd_content, std::shared_ptr< binder::cmd_option_bind_base > base_node)
size_type get_params_number() const
void load_cmd_array(const cmd_array_type &cmds)
const cmd_array_type & get_cmd_array() const
void set_ext_param(void *param)
void add(const char *param)
cmd_option_bind< std::string > cmd_option
Definition: cmd_option.h:639
cmd_option_bind< cmd_option_ci_string > cmd_option_ci
Definition: cmd_option.h:640
std::shared_ptr< cli::cmd_option_value > value_type
Definition: cmd_option.h:50
cmd_option_list & callback_param
导入高级库,hash、引用包装等 Licensed under the MIT licenses.
std::shared_ptr< cmd_option_bind_base > binded_obj