Commit 3f9fafd916e4ca20b4d05cfadea93c517d695f05

Authored by Philip Top
Committed by Henry Schreiner
1 parent 6ad2641d

make immediate_callback inheritable, add tests for that and for valid strings, s…

…ome cleanup in the README.md

Apply suggestions from code review

Co-Authored-By: phlptp <top1@llnl.gov>
allow callbacks for option_groups, and allow some other characters as flags
README.md
... ... @@ -236,7 +236,7 @@ Option_group *app.add_option_group(name,description); // 🚧
236 236 -app.add_mutable_set_ignore_case_underscore(... // πŸ†• String only
237 237 ```
238 238  
239   -An option name must start with a alphabetic character, underscore, or a number🚧. For long options, after the first character '.', and '-' are also valid. For the `add_flag*` functions '{' has special meaning. Names are given as a comma separated string, with the dash or dashes. An option or flag can have as many names as you want, and afterward, using `count`, you can use any of the names, with dashes as needed, to count the options. One of the names is allowed to be given without proceeding dash(es); if present the option is a positional option, and that name will be used on help line for its positional form. If you want the default value to print in the help description, pass in `true` for the final parameter for `add_option`.
  239 +An option name must start with a alphabetic character, underscore, a number 🚧, '?'🚧, or '@'🚧. For long options, after the first character '.', and '-' are also valid characters. For the `add_flag*` functions '{' has special meaning. Names are given as a comma separated string, with the dash or dashes. An option or flag can have as many names as you want, and afterward, using `count`, you can use any of the names, with dashes as needed, to count the options. One of the names is allowed to be given without proceeding dash(es); if present the option is a positional option, and that name will be used on help line for its positional form. If you want the default value to print in the help description, pass in `true` for the final parameter for `add_option`.
240 240  
241 241 The `add_option_function<type>(...` function will typically require the template parameter be given unless a `std::function` object with an exact match is passed. The type can be any type supported by the `add_option` function.
242 242  
... ... @@ -511,9 +511,10 @@ There are several options that are supported on the main app and subcommands and
511 511  
512 512 #### Callbacks
513 513 A subcommand has two optional callbacks that are executed at different stages of processing. The `preparse_callback` 🚧 is executed once after the first argument of a subcommand or application is processed and gives an argument for the number of remaining arguments to process. For the main app the first argument is considered the program name, for subcommands the first argument is the subcommand name. For Option groups and nameless subcommands the first argument is after the first argument or subcommand is processed from that group.
514   -The second callback is executed after parsing. Depending on the status of the `immediate_callback` flag 🚧. This is either immediately after the parsing of the subcommand. Or if the flag is false, once after parsing of all arguments. If the immediate_callback is set then the callback can be executed multiple times. If the main app or subcommand has a config file, no data from the config file will be reflected in immediate_callback.
  514 +The second callback is executed after parsing. The behavior depends on the status of the `immediate_callback` flag 🚧. If true, this runs immediately after the parsing of the subcommand. Or if the flag is false, once after parsing of all arguments. If the `immediate_callback` is set then the callback can be executed multiple times if the subcommand list given multiple times. If the main app or subcommand has a config file, no data from the config file will be reflected in immediate_callback. `immediate_callback()` has no effect on the main app, though it can be inherited. For option_groups `immediate_callback` causes the callback to be run prior to other option groups and options in the main app, effectively giving the options in the group priority.
515 515  
516 516 For example say an application was set up like
  517 +
517 518 ```cpp
518 519 app.callback(ac);
519 520 sub1=app.add_subcommand("sub1")->callback(c1)->preparse_callback(pc1)->immediate_callback();
... ... @@ -523,6 +524,7 @@ app.preparse_callback( pa1);
523 524 ... A bunch of other options
524 525  
525 526 ```
  527 +
526 528 Then the command line is given as
527 529  
528 530 ```
... ... @@ -534,8 +536,8 @@ program --opt1 opt1_val sub1 --sub1opt --sub1optb val sub2 --sub2opt sub1 --sub
534 536 * c1 will be called when the `sub2` command is encountered
535 537 * pc2 will be called with value of 6 after the sub2 command is encountered.
536 538 * c1 will be called again after the second sub2 command is encountered
537   -* ac will be called after completing the parse
538 539 * c2 will be called once after processing all arguments
  540 +* ac will be called after completing the parse and all lower level callbacks have been executed
539 541  
540 542 A subcommand is considered terminated when one of the following conditions are met.
541 543 1. There are no more arguments to process
... ... @@ -549,20 +551,26 @@ If the `immediate_callback` flag is set then all contained options are processed
549 551  
550 552 #### Option groups 🚧
551 553  
552   -The subcommand method
  554 +The subcommand method
  555 +
553 556 ```cpp
554 557 .add_option_group(name,description)
555 558 ```
  559 +
556 560 Will create an option Group, and return a pointer to it. An option group allows creation of a collection of options, similar to the groups function on options, but with additional controls and requirements. They allow specific sets of options to be composed and controlled as a collective. For an example see [range test](./tests/ranges.cpp). Option groups are a specialization of an App so all [functions](#subcommand-options) that work with an App also work on option groups. Options can be created as part of an option group using the add functions just like a subcommand, or previously created options can be added through
  561 +
557 562 ```cpp
558 563 ogroup->add_option(option_pointer)
559 564 ```
  565 +
560 566 ```cpp
561 567 ogroup->add_options(option_pointer)
562 568 ```
  569 +
563 570 ```cpp
564 571 ogroup->add_options(option1,option2,option3,...)
565 572 ```
  573 +
566 574 The option pointers used in this function must be options defined in the parent application of the option group otherwise an error will be generated.
567 575 Options in an option group are searched for a command line match after any options in the main app, so any positionals in the main app would be matched first. So care must be taken to make sure of the order when using positional arguments and option groups.
568 576 Option groups work well with `excludes` and `require_options` methods, as an Application will treat an option group as a single option for the purpose of counting and requirements. Option groups allow specifying requirements such as requiring 1 of 3 options in one group and 1 of 3 options in a different group. Option groups can contain other groups as well. Disabling an option group will turn off all options within the group.
... ... @@ -601,7 +609,7 @@ arguments, use `.config_to_str(default_also=false, prefix=&quot;&quot;, write_description=
601 609  
602 610 ### Inheriting defaults
603 611  
604   -Many of the defaults for subcommands and even options are inherited from their creators. The inherited default values for subcommands are `allow_extras`, `prefix_command`, `ignore_case`, πŸ†• `ignore_underscore`, `fallthrough`, `group`, `footer`, and maximum number of required subcommands. The help flag existence, name, and description are inherited, as well.
  612 +Many of the defaults for subcommands and even options are inherited from their creators. The inherited default values for subcommands are `allow_extras`, `prefix_command`, `ignore_case`, πŸ†• `ignore_underscore`, `fallthrough`, `group`, `footer`,`immediate_callback` and maximum number of required subcommands. The help flag existence, name, and description are inherited, as well.
605 613  
606 614 Options have defaults for `group`, `required`, `multi_option_policy`, `ignore_case`, πŸ†• `ignore_underscore`, 🚧 `delimiter`, and 🚧 `disable_flag_override`. To set these defaults, you should set the `option_defaults()` object, for example:
607 615  
... ...
include/CLI/App.hpp
... ... @@ -94,7 +94,7 @@ class App {
94 94 bool pre_parse_called_{false};
95 95  
96 96 /// Flag indicating that the callback for the subcommand should be executed immediately on parse completion which is
97   - /// before help or ini files are processed.
  97 + /// before help or ini files are processed. INHERITABLE
98 98 bool immediate_callback_{false};
99 99  
100 100 /// This is a function that runs prior to the start of parsing
... ... @@ -246,6 +246,7 @@ class App {
246 246 allow_extras_ = parent_->allow_extras_;
247 247 allow_config_extras_ = parent_->allow_config_extras_;
248 248 prefix_command_ = parent_->prefix_command_;
  249 + immediate_callback_ = parent_->immediate_callback_;
249 250 ignore_case_ = parent_->ignore_case_;
250 251 ignore_underscore_ = parent_->ignore_underscore_;
251 252 fallthrough_ = parent_->fallthrough_;
... ... @@ -320,7 +321,7 @@ class App {
320 321 return this;
321 322 }
322 323  
323   - /// Set the subcommand to be enabled by default, so on clear(), at the start of each parse it is enabled(not
  324 + /// Set the subcommand to be enabled by default, so on clear(), at the start of each parse it is enabled (not
324 325 /// disabled)
325 326 App *enabled_by_default(bool enable = true) {
326 327 enabled_by_default_ = enable;
... ... @@ -1778,15 +1779,26 @@ class App {
1778 1779 app->_configure();
1779 1780 }
1780 1781 }
1781   - /// Internal function to run (App) callback, top down
  1782 + /// Internal function to run (App) callback, bottom up
1782 1783 void run_callback() {
1783 1784 pre_callback();
1784   - if(callback_ && (parsed_ > 0))
1785   - callback_();
  1785 + // run the callbacks for the received subcommands
1786 1786 for(App *subc : get_subcommands()) {
1787   - if((subc->get_name().empty()) || (!subc->immediate_callback_))
  1787 + if(!subc->immediate_callback_)
1788 1788 subc->run_callback();
1789 1789 }
  1790 + // now run callbacks for option_groups
  1791 + for(auto &subc : subcommands_) {
  1792 + if(!subc->immediate_callback_ && subc->name_.empty() && subc->count_all() > 0) {
  1793 + subc->run_callback();
  1794 + }
  1795 + }
  1796 + // finally run the main callback
  1797 + if(callback_ && (parsed_ > 0)) {
  1798 + if(!name_.empty() || count_all() > 0) {
  1799 + callback_();
  1800 + }
  1801 + }
1790 1802 }
1791 1803  
1792 1804 /// Check to see if a subcommand is valid. Give up immediately if subcommand max has been reached.
... ... @@ -1817,7 +1829,7 @@ class App {
1817 1829 return detail::Classifier::SHORT;
1818 1830 if((allow_windows_style_options_) && (detail::split_windows_style(current, dummy1, dummy2)))
1819 1831 return detail::Classifier::WINDOWS;
1820   - if((current == "++") && (!name_.empty()))
  1832 + if((current == "++") && !name_.empty())
1821 1833 return detail::Classifier::SUBCOMMAND_TERMINATOR;
1822 1834 return detail::Classifier::NONE;
1823 1835 }
... ... @@ -1872,13 +1884,24 @@ class App {
1872 1884 }
1873 1885  
1874 1886 for(App_p &sub : subcommands_) {
1875   - if((sub->get_name().empty()) || (!sub->immediate_callback_))
  1887 + if(sub->get_name().empty() || !sub->immediate_callback_)
1876 1888 sub->_process_env();
1877 1889 }
1878 1890 }
1879 1891  
1880 1892 /// Process callbacks. Runs on *all* subcommands.
1881 1893 void _process_callbacks() {
  1894 +
  1895 + for(App_p &sub : subcommands_) {
  1896 + // process the priority option_groups first
  1897 + if(sub->get_name().empty() && sub->immediate_callback_) {
  1898 + if(sub->count_all() > 0) {
  1899 + sub->_process_callbacks();
  1900 + sub->run_callback();
  1901 + }
  1902 + }
  1903 + }
  1904 +
1882 1905 for(const Option_p &opt : options_) {
1883 1906 if(opt->count() > 0 && !opt->get_callback_run()) {
1884 1907 opt->run_callback();
... ... @@ -1886,8 +1909,9 @@ class App {
1886 1909 }
1887 1910  
1888 1911 for(App_p &sub : subcommands_) {
1889   - if((sub->get_name().empty()) || (!sub->immediate_callback_))
  1912 + if(!sub->immediate_callback_) {
1890 1913 sub->_process_callbacks();
  1914 + }
1891 1915 }
1892 1916 }
1893 1917  
... ... @@ -1979,13 +2003,12 @@ class App {
1979 2003 for(App_p &sub : subcommands_) {
1980 2004 if(sub->disabled_)
1981 2005 continue;
1982   - if((sub->name_.empty()) && (sub->count_all() > 0)) {
  2006 + if(sub->name_.empty() && sub->count_all() > 0) {
1983 2007 ++used_options;
1984 2008 }
1985 2009 }
1986 2010  
1987   - if((require_option_min_ > used_options) ||
1988   - ((require_option_max_ > 0) && (require_option_max_ < used_options))) {
  2011 + if(require_option_min_ > used_options || (require_option_max_ > 0 && require_option_max_ < used_options)) {
1989 2012 auto option_list = detail::join(options_, [](const Option_p &ptr) { return ptr->get_name(false, true); });
1990 2013 if(option_list.compare(0, 10, "-h,--help,") == 0) {
1991 2014 option_list.erase(0, 10);
... ... @@ -2001,25 +2024,25 @@ class App {
2001 2024 for(App_p &sub : subcommands_) {
2002 2025 if(sub->disabled_)
2003 2026 continue;
2004   - if((sub->name_.empty()) && (sub->required_ == false)) {
  2027 + if(sub->name_.empty() && sub->required_ == false) {
2005 2028 if(sub->count_all() == 0) {
2006   - if((require_option_min_ > 0) && (require_option_min_ <= used_options)) {
  2029 + if(require_option_min_ > 0 && require_option_min_ <= used_options) {
2007 2030 continue;
2008 2031 // if we have met the requirement and there is nothing in this option group skip checking
2009 2032 // requirements
2010 2033 }
2011   - if((require_option_max_ > 0) && (used_options >= require_option_min_)) {
  2034 + if(require_option_max_ > 0 && used_options >= require_option_min_) {
2012 2035 continue;
2013 2036 // if we have met the requirement and there is nothing in this option group skip checking
2014 2037 // requirements
2015 2038 }
2016 2039 }
2017 2040 }
2018   - if((sub->count() > 0) || (sub->name_.empty())) {
  2041 + if(sub->count() > 0 || sub->name_.empty()) {
2019 2042 sub->_process_requirements();
2020 2043 }
2021 2044  
2022   - if((sub->required_) && (sub->count_all() == 0)) {
  2045 + if(sub->required_ && sub->count_all() == 0) {
2023 2046 throw(CLI::RequiredError(sub->get_display_name()));
2024 2047 }
2025 2048 }
... ... @@ -2225,14 +2248,13 @@ class App {
2225 2248 }
2226 2249 }
2227 2250 }
2228   - /// let the parent deal with it if possible
  2251 + // let the parent deal with it if possible
2229 2252 if(parent_ != nullptr && fallthrough_)
2230 2253 return _get_fallthrough_parent()->_parse_positional(args);
2231 2254  
2232 2255 /// Try to find a local subcommand that is repeated
2233 2256 auto com = _find_subcommand(args.back(), true, false);
2234   - if((com != nullptr) &&
2235   - ((require_subcommand_max_ == 0) || (require_subcommand_max_ > parsed_subcommands_.size()))) {
  2257 + if(com != nullptr && (require_subcommand_max_ == 0 || require_subcommand_max_ > parsed_subcommands_.size())) {
2236 2258 args.pop_back();
2237 2259 com->_parse(args);
2238 2260 return true;
... ... @@ -2241,8 +2263,8 @@ class App {
2241 2263 /// subcommand in a broader way, if one exists let the parent deal with it
2242 2264 auto parent_app = (parent_ != nullptr) ? _get_fallthrough_parent() : this;
2243 2265 com = parent_app->_find_subcommand(args.back(), true, false);
2244   - if((com != nullptr) && ((com->parent_->require_subcommand_max_ == 0) ||
2245   - (com->parent_->require_subcommand_max_ > com->parent_->parsed_subcommands_.size()))) {
  2266 + if(com != nullptr && (com->parent_->require_subcommand_max_ == 0 ||
  2267 + com->parent_->require_subcommand_max_ > com->parent_->parsed_subcommands_.size())) {
2246 2268 return false;
2247 2269 }
2248 2270  
... ... @@ -2250,7 +2272,7 @@ class App {
2250 2272 throw CLI::ExtrasError(args);
2251 2273 }
2252 2274 /// If this is an option group don't deal with it
2253   - if((parent_ != nullptr) && (name_.empty())) {
  2275 + if(parent_ != nullptr && name_.empty()) {
2254 2276 return false;
2255 2277 }
2256 2278 /// We are out of other options this goes to missing
... ... @@ -2270,7 +2292,7 @@ class App {
2270 2292 /// subcommands be ignored
2271 2293 App *_find_subcommand(const std::string &subc_name, bool ignore_disabled, bool ignore_used) const noexcept {
2272 2294 for(const App_p &com : subcommands_) {
2273   - if((com->disabled_) && (ignore_disabled))
  2295 + if(com->disabled_ && ignore_disabled)
2274 2296 continue;
2275 2297 if(com->get_name().empty()) {
2276 2298 auto subc = com->_find_subcommand(subc_name, ignore_disabled, ignore_used);
... ... @@ -2278,7 +2300,7 @@ class App {
2278 2300 return subc;
2279 2301 }
2280 2302 } else if(com->check_name(subc_name)) {
2281   - if((!*com) || (!ignore_used))
  2303 + if((!*com) || !ignore_used)
2282 2304 return com.get();
2283 2305 }
2284 2306 }
... ... @@ -2353,7 +2375,7 @@ class App {
2353 2375 // Option not found
2354 2376 if(op_ptr == std::end(options_)) {
2355 2377 for(auto &subc : subcommands_) {
2356   - if((subc->name_.empty()) && (!(subc->disabled_))) {
  2378 + if(subc->name_.empty() && !subc->disabled_) {
2357 2379 if(subc->_parse_arg(args, current_type)) {
2358 2380 if(!subc->pre_parse_called_) {
2359 2381 subc->_trigger_pre_parse(args.size());
... ... @@ -2366,7 +2388,7 @@ class App {
2366 2388 if(parent_ != nullptr && fallthrough_)
2367 2389 return _get_fallthrough_parent()->_parse_arg(args, current_type);
2368 2390 // don't capture missing if this is a nameless subcommand
2369   - if((parent_ != nullptr) && (name_.empty())) {
  2391 + if(parent_ != nullptr && name_.empty()) {
2370 2392 return false;
2371 2393 }
2372 2394 // Otherwise, add to missing
... ...
include/CLI/Option.hpp
... ... @@ -667,7 +667,7 @@ class Option : public OptionBase&lt;Option&gt; {
667 667 // Run the validators (can change the string)
668 668 if(!validators_.empty()) {
669 669 for(std::string &result : results_)
670   - for(const std::function<std::string(std::string &)> &vali : validators_) {
  670 + for(const auto &vali : validators_) {
671 671 std::string err_msg;
672 672  
673 673 try {
... ...
include/CLI/StringTools.hpp
... ... @@ -171,12 +171,12 @@ inline std::ostream &amp;format_help(std::ostream &amp;out, std::string name, std::strin
171 171 }
172 172  
173 173 /// Verify the first character of an option
174   -template <typename T> bool valid_first_char(T c) { return std::isalnum(c, std::locale()) || c == '_'; }
  174 +template <typename T> bool valid_first_char(T c) {
  175 + return std::isalnum(c, std::locale()) || c == '_' || c == '?' || c == '@';
  176 +}
175 177  
176 178 /// Verify following characters of an option
177   -template <typename T> bool valid_later_char(T c) {
178   - return std::isalnum(c, std::locale()) || c == '_' || c == '.' || c == '-';
179   -}
  179 +template <typename T> bool valid_later_char(T c) { return valid_first_char(c) || c == '.' || c == '-'; }
180 180  
181 181 /// Verify an option name
182 182 inline bool valid_name_string(const std::string &str) {
... ...
tests/CreationTest.cpp
... ... @@ -472,6 +472,7 @@ TEST_F(TApp, SubcommandDefaults) {
472 472 // Initial defaults
473 473 EXPECT_FALSE(app.get_allow_extras());
474 474 EXPECT_FALSE(app.get_prefix_command());
  475 + EXPECT_FALSE(app.get_immediate_callback());
475 476 EXPECT_FALSE(app.get_ignore_case());
476 477 EXPECT_FALSE(app.get_ignore_underscore());
477 478 #ifdef _WIN32
... ... @@ -487,6 +488,7 @@ TEST_F(TApp, SubcommandDefaults) {
487 488  
488 489 app.allow_extras();
489 490 app.prefix_command();
  491 + app.immediate_callback();
490 492 app.ignore_case();
491 493 app.ignore_underscore();
492 494 #ifdef _WIN32
... ... @@ -505,6 +507,7 @@ TEST_F(TApp, SubcommandDefaults) {
505 507 // Initial defaults
506 508 EXPECT_TRUE(app2->get_allow_extras());
507 509 EXPECT_TRUE(app2->get_prefix_command());
  510 + EXPECT_TRUE(app2->get_immediate_callback());
508 511 EXPECT_TRUE(app2->get_ignore_case());
509 512 EXPECT_TRUE(app2->get_ignore_underscore());
510 513 #ifdef _WIN32
... ...
tests/HelpTest.cpp
... ... @@ -337,6 +337,17 @@ TEST(THelp, OnlyOneHelp) {
337 337 EXPECT_THROW(app.parse(input), CLI::ExtrasError);
338 338 }
339 339  
  340 +TEST(THelp, MultiHelp) {
  341 + CLI::App app{"My prog"};
  342 +
  343 + // It is not supported to have more than one help flag, last one wins
  344 + app.set_help_flag("--help,-h,-?", "No short name allowed");
  345 + app.allow_windows_style_options();
  346 +
  347 + std::vector<std::string> input{"/?"};
  348 + EXPECT_THROW(app.parse(input), CLI::CallForHelp);
  349 +}
  350 +
340 351 TEST(THelp, OnlyOneAllHelp) {
341 352 CLI::App app{"My prog"};
342 353  
... ...
tests/HelpersTest.cpp
... ... @@ -33,6 +33,10 @@ TEST(String, InvalidName) {
33 33 EXPECT_FALSE(CLI::detail::valid_name_string("vali&d"));
34 34 EXPECT_TRUE(CLI::detail::valid_name_string("_valid"));
35 35 EXPECT_FALSE(CLI::detail::valid_name_string("/valid"));
  36 + EXPECT_TRUE(CLI::detail::valid_name_string("vali?d"));
  37 + EXPECT_TRUE(CLI::detail::valid_name_string("@@@@"));
  38 + EXPECT_TRUE(CLI::detail::valid_name_string("b@d2?"));
  39 + EXPECT_TRUE(CLI::detail::valid_name_string("2vali?d"));
36 40 }
37 41  
38 42 TEST(StringTools, Modify) {
... ...
tests/OptionGroupTest.cpp
... ... @@ -550,6 +550,30 @@ TEST_F(ManyGroups, SameSubcommand) {
550 550 EXPECT_EQ(subs[1], sub2);
551 551 EXPECT_EQ(subs[2], sub3);
552 552 }
  553 +TEST_F(ManyGroups, CallbackOrder) {
  554 + // only 1 group can be used
  555 + remove_required();
  556 + std::vector<int> callback_order;
  557 + g1->callback([&callback_order]() { callback_order.push_back(1); });
  558 + g2->callback([&callback_order]() { callback_order.push_back(2); });
  559 + main->callback([&callback_order]() { callback_order.push_back(3); });
  560 +
  561 + args = {"--name2", "test"};
  562 + run();
  563 + EXPECT_EQ(callback_order, std::vector<int>({2, 3}));
  564 +
  565 + callback_order.clear();
  566 + args = {"--name1", "t2", "--name2", "test"};
  567 + g2->immediate_callback();
  568 + run();
  569 + EXPECT_EQ(callback_order, std::vector<int>({2, 1, 3}));
  570 + callback_order.clear();
  571 +
  572 + args = {"--name2", "test", "--name1", "t2"};
  573 + g2->immediate_callback(false);
  574 + run();
  575 + EXPECT_EQ(callback_order, std::vector<int>({1, 2, 3}));
  576 +}
553 577  
554 578 struct ManyGroupsPreTrigger : public ManyGroups {
555 579 size_t triggerMain, trigger1{87u}, trigger2{34u}, trigger3{27u};
... ...
tests/SubcommandTest.cpp
... ... @@ -908,6 +908,22 @@ TEST_F(SubcommandProgram, CallbackOrder) {
908 908 EXPECT_EQ(callback_order, std::vector<int>({2, 1}));
909 909 }
910 910  
  911 +TEST_F(SubcommandProgram, CallbackOrderImmediate) {
  912 + std::vector<int> callback_order;
  913 + start->callback([&callback_order]() { callback_order.push_back(1); })->immediate_callback();
  914 + stop->callback([&callback_order]() { callback_order.push_back(2); });
  915 +
  916 + args = {"start", "stop", "start"};
  917 + run();
  918 + EXPECT_EQ(callback_order, std::vector<int>({1, 1, 2}));
  919 +
  920 + callback_order.clear();
  921 +
  922 + args = {"stop", "start", "stop", "start"};
  923 + run();
  924 + EXPECT_EQ(callback_order, std::vector<int>({1, 1, 2}));
  925 +}
  926 +
911 927 struct ManySubcommands : public TApp {
912 928  
913 929 CLI::App *sub1;
... ...