diff --git a/CHANGELOG.md b/CHANGELOG.md index d2a59b4..83f94ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,10 +15,15 @@ * Bugfix: avoid listing helpall as a required flag [#530][] * Bugfix: avoid a clash with WINDOWS define [#563][] -* Removed deprecated set commands, use validators instead. [#565][] - * Build: support pkg-config [#523][] +#### Converting from CLI11 1.9: + +* Removed deprecated set commands, use validators instead. [#565][] +* The final "defaulted" bool has been removed, use `->capture_default_str()` + instead. Use `app.option_defaults()->always_capture_default()` to set this for + all future options. [#597][] + [#435]: https://github.com/CLIUtils/CLI11/pull/435 [#443]: https://github.com/CLIUtils/CLI11/pull/443 @@ -35,6 +40,7 @@ [#563]: https://github.com/CLIUtils/CLI11/pull/563 [#565]: https://github.com/CLIUtils/CLI11/pull/565 [#574]: https://github.com/CLIUtils/CLI11/pull/574 +[#597]: https://github.com/CLIUtils/CLI11/pull/597 @@ -136,6 +142,7 @@ configuration options were added to facilitate a wider variety of apps. GCC [#360]: https://github.com/CLIUtils/CLI11/pull/360 [#362]: https://github.com/CLIUtils/CLI11/pull/362 [#365]: https://github.com/CLIUtils/CLI11/pull/365 +[#370]: https://github.com/CLIUtils/CLI11/pull/370 [#373]: https://github.com/CLIUtils/CLI11/pull/373 [#374]: https://github.com/CLIUtils/CLI11/pull/374 [#382]: https://github.com/CLIUtils/CLI11/pull/382 diff --git a/book/chapters/options.md b/book/chapters/options.md index 961188e..ba1eed7 100644 --- a/book/chapters/options.md +++ b/book/chapters/options.md @@ -9,11 +9,11 @@ int int_option{0}; app.add_option("-i", int_option, "Optional description"); ``` -This will bind the option `-i` to the integer `int_option`. On the command line, a single value that can be converted to an integer will be expected. Non-integer results will fail. If that option is not given, CLI11 will not touch the initial value. This allows you to set up defaults by simply setting your value beforehand. If you want CLI11 to display your default value, you can add the optional final argument `true` when you add the option. +This will bind the option `-i` to the integer `int_option`. On the command line, a single value that can be converted to an integer will be expected. Non-integer results will fail. If that option is not given, CLI11 will not touch the initial value. This allows you to set up defaults by simply setting your value beforehand. If you want CLI11 to display your default value, you can add `->capture_default_str()` after the option. ```cpp int int_option{0}; -app.add_option("-i", int_option, "Optional description", true); +app.add_option("-i", int_option, "Optional description")->capture_default_str(); ``` You can use any C++ int-like type, not just `int`. CLI11 understands the following categories of types: diff --git a/examples/nested.cpp b/examples/nested.cpp index 23f4285..97f3429 100644 --- a/examples/nested.cpp +++ b/examples/nested.cpp @@ -18,7 +18,9 @@ int main(int argc, char **argv) { std::string mvcamera_config_file = "mvcamera_config.json"; CLI::App *mvcameraApp = cameraApp->add_subcommand("mvcamera", "MatrixVision Camera Configuration"); - mvcameraApp->add_option("-c,--config", mvcamera_config_file, "Config filename", true)->check(CLI::ExistingFile); + mvcameraApp->add_option("-c,--config", mvcamera_config_file, "Config filename") + ->capture_default_str() + ->check(CLI::ExistingFile); std::string mock_camera_path; CLI::App *mockcameraApp = cameraApp->add_subcommand("mock", "Mock Camera Configuration"); diff --git a/examples/ranges.cpp b/examples/ranges.cpp index 085a7ad..37032e6 100644 --- a/examples/ranges.cpp +++ b/examples/ranges.cpp @@ -19,7 +19,7 @@ int main(int argc, char **argv) { int min{0}, max{0}, step{1}; ogroup->add_option("--min,-m", min, "The minimum")->required(); ogroup->add_option("--max,-M", max, "The maximum")->required(); - ogroup->add_option("--step,-s", step, "The step", true); + ogroup->add_option("--step,-s", step, "The step")->capture_default_str(); app.require_option(1); diff --git a/include/CLI/App.hpp b/include/CLI/App.hpp index edbe2b7..acae2a1 100644 --- a/include/CLI/App.hpp +++ b/include/CLI/App.hpp @@ -611,14 +611,13 @@ class App { enable_if_t::value, detail::enabler> = detail::dummy> Option *add_option(std::string option_name, AssignTo &variable, ///< The variable to set - std::string option_description = "", - bool defaulted = false) { + std::string option_description = "") { auto fun = [&variable](const CLI::results_t &res) { // comment for spacing return detail::lexical_conversion(res, variable); }; - Option *opt = add_option(option_name, fun, option_description, defaulted, [&variable]() { + Option *opt = add_option(option_name, fun, option_description, false, [&variable]() { return CLI::detail::checked_to_string(variable); }); opt->type_name(detail::type_name()); diff --git a/test_package/example.cpp b/test_package/example.cpp index beb97fe..464cf75 100644 --- a/test_package/example.cpp +++ b/test_package/example.cpp @@ -9,7 +9,7 @@ int main(int argc, char **argv) { CLI::App app("Some nice description"); int x = 0; - app.add_option("-x", x, "an integer value", true /* show default */); + app.add_option("-x", x, "an integer value")->capture_default_str(); bool flag; app.add_flag("-f,--flag", flag, "a flag option"); diff --git a/tests/AppTest.cpp b/tests/AppTest.cpp index 6c3e71c..d5e6c38 100644 --- a/tests/AppTest.cpp +++ b/tests/AppTest.cpp @@ -2219,7 +2219,7 @@ TEST_CASE_METHOD(TApp, "CustomUserSepParse3", "[app]") { CHECK(std::vector({1, 2}) == vals); app.remove_option(opt); - app.add_option("--idx", vals, "", false)->delimiter(','); + app.add_option("--idx", vals)->delimiter(','); run(); CHECK(std::vector({1, 2}) == vals); } diff --git a/tests/ConfigFileTest.cpp b/tests/ConfigFileTest.cpp index 12fa88c..afe1705 100644 --- a/tests/ConfigFileTest.cpp +++ b/tests/ConfigFileTest.cpp @@ -1685,7 +1685,7 @@ TEST_CASE_METHOD(TApp, "TomlOutputHiddenOptions", "[config]") { const std::string description2 = "Second description."; app.add_flag("--" + flag1, description1)->group("group1"); app.add_flag("--" + flag2, description2)->group("group2"); - app.add_option("--dval", val, "", true)->group(""); + app.add_option("--dval", val)->capture_default_str()->group(""); run(); @@ -1723,7 +1723,7 @@ TEST_CASE_METHOD(TApp, "TomlOutputOptionGroup", "[config]") { app.add_flag("--" + flag1, description1)->group("group1"); app.add_flag("--" + flag2, description2)->group("group2"); auto og = app.add_option_group("group3", "g3 desc"); - og->add_option("--dval", val, "", true)->group(""); + og->add_option("--dval", val)->capture_default_str()->group(""); run(); @@ -1809,7 +1809,7 @@ TEST_CASE_METHOD(TApp, "TomlOutputSet", "[config]") { TEST_CASE_METHOD(TApp, "TomlOutputDefault", "[config]") { int v{7}; - app.add_option("--simple", v, "", true); + app.add_option("--simple", v)->capture_default_str(); run(); @@ -1934,10 +1934,10 @@ TEST_CASE_METHOD(TApp, "TomlOutputQuoted", "[config]") { TEST_CASE_METHOD(TApp, "DefaultsTomlOutputQuoted", "[config]") { std::string val1{"I am a string"}; - app.add_option("--val1", val1, "", true); + app.add_option("--val1", val1)->capture_default_str(); std::string val2{R"(I am a "confusing" string)"}; - app.add_option("--val2", val2, "", true); + app.add_option("--val2", val2)->capture_default_str(); run(); @@ -2068,7 +2068,7 @@ TEST_CASE_METHOD(TApp, "IniOutputHiddenOptions", "[config]") { const std::string description2 = "Second description."; app.add_flag("--" + flag1, description1)->group("group1"); app.add_flag("--" + flag2, description2)->group("group2"); - app.add_option("--dval", val, "", true)->group(""); + app.add_option("--dval", val)->capture_default_str()->group(""); app.config_formatter(std::make_shared()); run(); @@ -2106,7 +2106,7 @@ TEST_CASE_METHOD(TApp, "IniOutputOptionGroup", "[config]") { app.add_flag("--" + flag1, description1)->group("group1"); app.add_flag("--" + flag2, description2)->group("group2"); auto og = app.add_option_group("group3", "g3 desc"); - og->add_option("--dval", val, "", true)->group(""); + og->add_option("--dval", val)->capture_default_str()->group(""); app.config_formatter(std::make_shared()); run(); @@ -2177,7 +2177,7 @@ TEST_CASE_METHOD(TApp, "IniOutputSet", "[config]") { TEST_CASE_METHOD(TApp, "IniOutputDefault", "[config]") { int v{7}; - app.add_option("--simple", v, "", true); + app.add_option("--simple", v)->capture_default_str(); app.config_formatter(std::make_shared()); run(); @@ -2302,10 +2302,10 @@ TEST_CASE_METHOD(TApp, "IniOutputQuoted", "[config]") { TEST_CASE_METHOD(TApp, "DefaultsIniOutputQuoted", "[config]") { std::string val1{"I am a string"}; - app.add_option("--val1", val1, "", true); + app.add_option("--val1", val1)->capture_default_str(); std::string val2{R"(I am a "confusing" string)"}; - app.add_option("--val2", val2, "", true); + app.add_option("--val2", val2)->capture_default_str(); app.config_formatter(std::make_shared()); run(); diff --git a/tests/CreationTest.cpp b/tests/CreationTest.cpp index 2a70f70..0e6e45d 100644 --- a/tests/CreationTest.cpp +++ b/tests/CreationTest.cpp @@ -739,13 +739,13 @@ TEST_CASE_METHOD(TApp, "MakeUnstreamableOptions", "[creation]") { app.add_option("--value", value); // This used to fail to build, since it tries to stream from Unstreamable - app.add_option("--value2", value, "", false); + app.add_option("--value2", value); std::vector values; app.add_option("--values", values); // This used to fail to build, since it tries to stream from Unstreamable - app.add_option("--values2", values, "", false); + app.add_option("--values2", values); args = {"--value", "45"}; run(); diff --git a/tests/DeprecatedTest.cpp b/tests/DeprecatedTest.cpp index cf9987c..a25224c 100644 --- a/tests/DeprecatedTest.cpp +++ b/tests/DeprecatedTest.cpp @@ -12,214 +12,3 @@ TEST_CASE("Deprecated: Empty", "[deprecated]") { // No deprecated features at this time. CHECK(true); } - -// Classic sets - -TEST_CASE("THelp: Defaults", "[deprecated]") { - CLI::App app{"My prog"}; - - int one{1}, two{2}; - app.add_option("--one", one, "Help for one", true); - app.add_option("--set", two, "Help for set", true)->check(CLI::IsMember({2, 3, 4})); - - std::string help = app.help(); - - CHECK_THAT(help, Contains("--one")); - CHECK_THAT(help, Contains("--set")); - CHECK_THAT(help, Contains("1")); - CHECK_THAT(help, Contains("=2")); - CHECK_THAT(help, Contains("2,3,4")); -} - -TEST_CASE("THelp: VectorOpts", "[deprecated]") { - CLI::App app{"My prog"}; - std::vector x = {1, 2}; - app.add_option("-q,--quick", x, "", true); - - std::string help = app.help(); - - CHECK_THAT(help, Contains("INT=[1,2] ...")); -} - -TEST_CASE("THelp: SetLower", "[deprecated]") { - CLI::App app{"My prog"}; - - std::string def{"One"}; - app.add_option("--set", def, "Help for set", true)->check(CLI::IsMember({"oNe", "twO", "THREE"})); - - std::string help = app.help(); - - CHECK_THAT(help, Contains("--set")); - CHECK_THAT(help, Contains("=One")); - CHECK_THAT(help, Contains("oNe")); - CHECK_THAT(help, Contains("twO")); - CHECK_THAT(help, Contains("THREE")); -} - -TEST_CASE("THelp: ChangingSetDefaulted", "[deprecated]") { - CLI::App app; - - std::set vals{1, 2, 3}; - int val = 2; - app.add_option("--val", val, "", true)->check(CLI::IsMember(&vals)); - - std::string help = app.help(); - - CHECK_THAT(help, Contains("1")); - CHECK_THAT(help, !Contains("4")); - - vals.insert(4); - vals.erase(1); - - help = app.help(); - - CHECK_THAT(help, !Contains("1")); - CHECK_THAT(help, Contains("4")); -} - -TEST_CASE("THelp: ChangingCaselessSetDefaulted", "[deprecated]") { - CLI::App app; - - std::set vals{"1", "2", "3"}; - std::string val = "2"; - app.add_option("--val", val, "", true)->check(CLI::IsMember(&vals, CLI::ignore_case)); - - std::string help = app.help(); - - CHECK_THAT(help, Contains("1")); - CHECK_THAT(help, !Contains("4")); - - vals.insert("4"); - vals.erase("1"); - - help = app.help(); - - CHECK_THAT(help, !Contains("1")); - CHECK_THAT(help, Contains("4")); -} - -TEST_CASE_METHOD(TApp, "DefaultOpts", "[deprecated]") { - - int i = 3; - std::string s = "HI"; - - app.add_option("-i,i", i, "", false); - app.add_option("-s,s", s, "", true); - - args = {"-i2", "9"}; - - run(); - - CHECK(app.count("i") == 1u); - CHECK(app.count("-s") == 1u); - CHECK(i == 2); - CHECK(s == "9"); -} - -TEST_CASE_METHOD(TApp, "VectorDefaultedFixedString", "[deprecated]") { - std::vector strvec{"one"}; - std::vector answer{"mystring", "mystring2", "mystring3"}; - - CLI::Option *opt = app.add_option("-s,--string", strvec, "", true)->expected(3); - CHECK(opt->get_expected() == 3); - - args = {"--string", "mystring", "mystring2", "mystring3"}; - run(); - CHECK(app.count("--string") == 3u); - CHECK(strvec == answer); -} - -TEST_CASE_METHOD(TApp, "DefaultedResult", "[deprecated]") { - std::string sval = "NA"; - int ival; - auto opts = app.add_option("--string", sval, "", true); - auto optv = app.add_option("--val", ival); - args = {}; - run(); - CHECK("NA" == sval); - std::string nString; - opts->results(nString); - CHECK("NA" == nString); - int newIval; - // CHECK_THROWS_AS (optv->results(newIval), CLI::ConversionError); - optv->default_str("442"); - optv->results(newIval); - CHECK(442 == newIval); -} - -TEST_CASE_METHOD(TApp, "OptionWithDefaults", "[deprecated]") { - int someint = 2; - app.add_option("-a", someint, "", true); - - args = {"-a1", "-a2"}; - - CHECK_THROWS_AS(run(), CLI::ArgumentMismatch); -} - -// #209 -TEST_CASE_METHOD(TApp, "CustomUserSepParse", "[deprecated]") { - - std::vector vals = {1, 2, 3}; - args = {"--idx", "1,2,3"}; - auto opt = app.add_option("--idx", vals)->delimiter(','); - run(); - CHECK(std::vector({1, 2, 3}) == vals); - std::vector vals2; - // check that the results vector gets the results in the same way - opt->results(vals2); - CHECK(vals == vals2); - - app.remove_option(opt); - - app.add_option("--idx", vals, "", true)->delimiter(','); - run(); - CHECK(std::vector({1, 2, 3}) == vals); -} - -// #209 -TEST_CASE_METHOD(TApp, "CustomUserSepParse2", "[deprecated]") { - - std::vector vals = {1, 2, 3}; - args = {"--idx", "1,2,"}; - auto opt = app.add_option("--idx", vals)->delimiter(','); - run(); - CHECK(std::vector({1, 2}) == vals); - - app.remove_option(opt); - - app.add_option("--idx", vals, "", true)->delimiter(','); - run(); - CHECK(std::vector({1, 2}) == vals); -} -// -// #209 -TEST_CASE_METHOD(TApp, "CustomUserSepParse4", "[deprecated]") { - - std::vector vals; - args = {"--idx", "1, 2"}; - auto opt = app.add_option("--idx", vals, "", true)->delimiter(','); - run(); - CHECK(std::vector({1, 2}) == vals); - - app.remove_option(opt); - - app.add_option("--idx", vals)->delimiter(','); - run(); - CHECK(std::vector({1, 2}) == vals); -} - -// #218 -TEST_CASE_METHOD(TApp, "CustomUserSepParse5", "[deprecated]") { - - std::vector bar; - args = {"this", "is", "a", "test"}; - auto opt = app.add_option("bar", bar, "bar"); - run(); - CHECK(std::vector({"this", "is", "a", "test"}) == bar); - - app.remove_option(opt); - args = {"this", "is", "a", "test"}; - app.add_option("bar", bar, "bar", true); - run(); - CHECK(std::vector({"this", "is", "a", "test"}) == bar); -} diff --git a/tests/NewParseTest.cpp b/tests/NewParseTest.cpp index d9d9dbf..6e88fee 100644 --- a/tests/NewParseTest.cpp +++ b/tests/NewParseTest.cpp @@ -35,7 +35,7 @@ TEST_CASE_METHOD(TApp, "Complex", "[newparse]") { TEST_CASE_METHOD(TApp, "ComplexOption", "[newparse]") { cx comp{1, 2}; - app.add_option("-c,--complex", comp, "", true); + app.add_option("-c,--complex", comp)->capture_default_str(); args = {"-c", "4", "3"}; @@ -55,7 +55,7 @@ TEST_CASE_METHOD(TApp, "ComplexOption", "[newparse]") { TEST_CASE_METHOD(TApp, "ComplexFloat", "[newparse]") { std::complex comp{1, 2}; - app.add_complex, float>("-c,--complex", comp, "", true); + app.add_complex, float>("-c,--complex", comp)->capture_default_str(); args = {"-c", "4", "3"}; @@ -75,7 +75,7 @@ TEST_CASE_METHOD(TApp, "ComplexFloat", "[newparse]") { TEST_CASE_METHOD(TApp, "ComplexFloatOption", "[newparse]") { std::complex comp{1, 2}; - app.add_option("-c,--complex", comp, "", true); + app.add_option("-c,--complex", comp)->capture_default_str(); args = {"-c", "4", "3"}; @@ -95,7 +95,7 @@ TEST_CASE_METHOD(TApp, "ComplexFloatOption", "[newparse]") { TEST_CASE_METHOD(TApp, "ComplexWithDelimiter", "[newparse]") { cx comp{1, 2}; - app.add_complex("-c,--complex", comp, "", true)->delimiter('+'); + app.add_complex("-c,--complex", comp)->capture_default_str()->delimiter('+'); args = {"-c", "4+3i"}; @@ -127,7 +127,7 @@ TEST_CASE_METHOD(TApp, "ComplexWithDelimiter", "[newparse]") { TEST_CASE_METHOD(TApp, "ComplexWithDelimiterOption", "[newparse]") { cx comp{1, 2}; - app.add_option("-c,--complex", comp, "", true)->delimiter('+'); + app.add_option("-c,--complex", comp)->capture_default_str()->delimiter('+'); args = {"-c", "4+3i"}; diff --git a/tests/OptionTypeTest.cpp b/tests/OptionTypeTest.cpp index a2f893b..3204d52 100644 --- a/tests/OptionTypeTest.cpp +++ b/tests/OptionTypeTest.cpp @@ -240,7 +240,7 @@ TEST_CASE_METHOD(TApp, "CharOption", "[optiontype]") { TEST_CASE_METHOD(TApp, "vectorDefaults", "[optiontype]") { std::vector vals{4, 5}; - auto opt = app.add_option("--long", vals, "", true); + auto opt = app.add_option("--long", vals)->capture_default_str(); args = {"--long", "[1,2,3]"}; diff --git a/tests/SetTest.cpp b/tests/SetTest.cpp index d34a67a..bd817b7 100644 --- a/tests/SetTest.cpp +++ b/tests/SetTest.cpp @@ -373,7 +373,7 @@ TEST_CASE_METHOD(TApp, "NumericalSets", "[set]") { TEST_CASE_METHOD(TApp, "SetWithDefaults", "[set]") { int someint{2}; - app.add_option("-a", someint, "", true)->check(CLI::IsMember({1, 2, 3, 4})); + app.add_option("-a", someint)->capture_default_str()->check(CLI::IsMember({1, 2, 3, 4})); args = {"-a1", "-a2"}; @@ -382,7 +382,7 @@ TEST_CASE_METHOD(TApp, "SetWithDefaults", "[set]") { TEST_CASE_METHOD(TApp, "SetWithDefaultsConversion", "[set]") { int someint{2}; - app.add_option("-a", someint, "", true)->check(CLI::IsMember({1, 2, 3, 4})); + app.add_option("-a", someint)->capture_default_str()->check(CLI::IsMember({1, 2, 3, 4})); args = {"-a", "hi"}; @@ -391,7 +391,7 @@ TEST_CASE_METHOD(TApp, "SetWithDefaultsConversion", "[set]") { TEST_CASE_METHOD(TApp, "SetWithDefaultsIC", "[set]") { std::string someint = "ho"; - app.add_option("-a", someint, "", true)->check(CLI::IsMember({"Hi", "Ho"})); + app.add_option("-a", someint)->capture_default_str()->check(CLI::IsMember({"Hi", "Ho"})); args = {"-aHi", "-aHo"}; @@ -415,7 +415,7 @@ TEST_CASE_METHOD(TApp, "InSet", "[set]") { TEST_CASE_METHOD(TApp, "InSetWithDefault", "[set]") { std::string choice = "one"; - app.add_option("-q,--quick", choice, "", true)->check(CLI::IsMember({"one", "two", "three"})); + app.add_option("-q,--quick", choice)->capture_default_str()->check(CLI::IsMember({"one", "two", "three"})); run(); CHECK(choice == "one"); @@ -432,7 +432,9 @@ TEST_CASE_METHOD(TApp, "InSetWithDefault", "[set]") { TEST_CASE_METHOD(TApp, "InCaselessSetWithDefault", "[set]") { std::string choice = "one"; - app.add_option("-q,--quick", choice, "", true)->transform(CLI::IsMember({"one", "two", "three"}, CLI::ignore_case)); + app.add_option("-q,--quick", choice) + ->capture_default_str() + ->transform(CLI::IsMember({"one", "two", "three"}, CLI::ignore_case)); run(); CHECK(choice == "one"); @@ -494,7 +496,7 @@ TEST_CASE_METHOD(TApp, "FailMutableSet", "[set]") { int choice{0}; auto vals = std::shared_ptr>(new std::set({1, 2, 3})); app.add_option("-q,--quick", choice)->check(CLI::IsMember(vals)); - app.add_option("-s,--slow", choice, "", true)->check(CLI::IsMember(vals)); + app.add_option("-s,--slow", choice)->capture_default_str()->check(CLI::IsMember(vals)); args = {"--quick=hello"}; CHECK_THROWS_AS(run(), CLI::ValidationError); @@ -651,7 +653,7 @@ TEST_CASE_METHOD(TApp, "AddRemoveSetItems", "[set]") { std::string type1, type2; app.add_option("--type1", type1)->check(CLI::IsMember(&items)); - app.add_option("--type2", type2, "", true)->check(CLI::IsMember(&items)); + app.add_option("--type2", type2)->capture_default_str()->check(CLI::IsMember(&items)); args = {"--type1", "TYPE1", "--type2", "TYPE2"}; @@ -682,7 +684,7 @@ TEST_CASE_METHOD(TApp, "AddRemoveSetItemsNoCase", "[set]") { std::string type1, type2; app.add_option("--type1", type1)->transform(CLI::IsMember(&items, CLI::ignore_case)); - app.add_option("--type2", type2, "", true)->transform(CLI::IsMember(&items, CLI::ignore_case)); + app.add_option("--type2", type2)->capture_default_str()->transform(CLI::IsMember(&items, CLI::ignore_case)); args = {"--type1", "TYPe1", "--type2", "TyPE2"}; diff --git a/tests/SubcommandTest.cpp b/tests/SubcommandTest.cpp index eef67bc..c17013b 100644 --- a/tests/SubcommandTest.cpp +++ b/tests/SubcommandTest.cpp @@ -109,7 +109,7 @@ TEST_CASE_METHOD(TApp, "CrazyNameSubcommand", "[subcom]") { TEST_CASE_METHOD(TApp, "RequiredAndSubcommands", "[subcom]") { std::string baz; - app.add_option("baz", baz, "Baz Description", true)->required(); + app.add_option("baz", baz, "Baz Description")->required()->capture_default_str(); auto foo = app.add_subcommand("foo"); auto bar = app.add_subcommand("bar");