{"id":15047772,"url":"https://github.com/daishe/commander","last_synced_at":"2026-01-01T22:34:00.459Z","repository":{"id":140101985,"uuid":"105538336","full_name":"daishe/commander","owner":"daishe","description":"The variation of the command design pattern","archived":false,"fork":false,"pushed_at":"2017-10-02T13:38:48.000Z","size":130,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-01-20T18:33:12.559Z","etag":null,"topics":["argument-parsing","c-plus-plus","cpp","cpp17","cpp1z","design-pattern","header-only","metaprogramming","program-options","template-metaprogramming"],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/daishe.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-10-02T13:37:44.000Z","updated_at":"2017-10-02T13:42:21.000Z","dependencies_parsed_at":null,"dependency_job_id":"8c141e6f-418d-41db-81fd-93767652c46a","html_url":"https://github.com/daishe/commander","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daishe%2Fcommander","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daishe%2Fcommander/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daishe%2Fcommander/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daishe%2Fcommander/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/daishe","download_url":"https://codeload.github.com/daishe/commander/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243495495,"owners_count":20299923,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["argument-parsing","c-plus-plus","cpp","cpp17","cpp1z","design-pattern","header-only","metaprogramming","program-options","template-metaprogramming"],"created_at":"2024-09-24T21:04:21.398Z","updated_at":"2026-01-01T22:34:00.368Z","avatar_url":"https://github.com/daishe.png","language":"C++","readme":"# Commander - the variation of the command design pattern\n\n## Example\nAll example files can be compiled and executed on their own (you only need commander headers).\n\n### rectangle_painter\nLet's take a first simplest example the rectangle_painter command. As the name suggests - it will print to stdout rectangle.\n\nThe class (and its usage) could look like this:\n```cpp\n#include \u003ciostream\u003e\n#include \u003cutility\u003e\n\ntemplate \u003ctypename Length\u003e\nclass rectangle_painter\n{\n    public:\n        using length_type = Length;\n\n        void operator ()() const\n        {\n            for (length_type y = 0; y \u003c this-\u003elength_.second; ++y) {\n                for (length_type x = 0; x \u003c this-\u003elength_.first; ++x)\n                    std::cout \u003c\u003c this-\u003efill_;\n                std::cout \u003c\u003c '\\n';\n            }\n        };\n\n        void fill(char f)\n        { this-\u003efill_ = f; };\n\n        void x(const length_type\u0026 xl)\n        { this-\u003elength_.first = xl; };\n\n        void y(const length_type\u0026 yl)\n        { this-\u003elength_.second = yl; };\n\n    private:\n        std::pair\u003clength_type, length_type\u003e length_ = std::pair\u003clength_type, length_type\u003e(0, 0);\n        char fill_ = char(' ');\n};\n\nint main(int /*argc*/, const char ** /*argv*/)\n{\n    rectangle_painter\u003cint\u003e rp;\n    rp.x(8);\n    rp.y(3);\n    rp.fill('x');\n    rp();\n}\n```\nEverything is ok. It isn't general interface, but it works.\n\nLet's assume that later we extend the architecture of our application. We introduce other classes (for example circle and square) and value checks to all set functions. So we need to create some exception type (of course we can return boolean value with would indicate failure, but then it would be the caller problem). Also using all classes is a problem (each has a different interface) even in template code.  The usage quickly gets kind of clumsy. It is especially painful if those are some important and large pieces in an application.\n\n### rectangle_painter with console-like interface\nCommander approach is to enable the ability to embed console-like interface.\n```cpp\n#include \u003carray\u003e\n#include \u003ciostream\u003e\n#include \u003cstring\u003e\n#include \u003cstring_view\u003e\n#include \u003cutility\u003e\n\n#include \u003cboost/lexical_cast.hpp\u003e\n#include \u003ccommander.hpp\u003e\n\ntemplate \u003ctypename Length\u003e\nclass rectangle_painter\n{\n    public:\n        using length_type = Length;\n\n        template \u003ctypename... Types\u003e\n        void operator ()(Types\u0026\u0026... values)\n        {\n            if constexpr (sizeof...(values) != 0)\n                ((*this) \u003c\u003c values \u003c\u003c ...);\n\n            this-\u003eparser_();\n            for (length_type y = 0; y \u003c this-\u003elength_.second; ++y) {\n                for (length_type x = 0; x \u003c this-\u003elength_.first; ++x)\n                    std::cout \u003c\u003c this-\u003efill_;\n                std::cout \u003c\u003c '\\n';\n            }\n        }\n\n        template \u003ctypename T\u003e\n        rectangle_painter\u003clength_type\u003e\u0026 operator \u003c\u003c(T\u0026\u0026 value)\n        {\n            if constexpr (commander::func::is_exec_v(value)) {\n                value(*this);\n            }\n            else {\n                auto tup = std::make_tuple(\n                    commander::make_empty_storage(\n                        commander::no_value,\n                        [](const std::string_view\u0026 header) { return commander::compare_disjunction(header, \"-x\", \"-w\", \"--width\"); },\n                        commander::make_applier(\n                            [this](const length_type\u0026 xl) { this-\u003elength_.first = xl; return true; },\n                            [this](const std::string_view\u0026 xl) { this-\u003elength_.first = boost::lexical_cast\u003clength_type\u003e(xl); return true; }\n                        )\n                    ),\n                    commander::make_empty_storage(\n                        commander::no_value,\n                        [](const std::string_view\u0026 header) { return commander::compare_disjunction(header, \"-y\", \"-h\", \"--height\"); },\n                        commander::make_applier(\n                            [this](const length_type\u0026 yl) { this-\u003elength_.second = yl; return true; },\n                            [this](const std::string_view\u0026 yl) { this-\u003elength_.second = boost::lexical_cast\u003clength_type\u003e(yl); return true; }\n                        )\n                    ),\n                    commander::make_empty_storage(\n                        commander::no_value,\n                        [](const std::string_view\u0026 header) { return commander::compare_disjunction(header, \"-f\", \"--fill\"); },\n                        commander::make_applier(\n                            [this](const char\u0026 f) { this-\u003efill_ = f; return true; },\n                            [this](const std::string_view\u0026 f) { this-\u003efill_ = boost::lexical_cast\u003cchar\u003e(f); return true; }\n                        )\n                    )\n                );\n\n                this-\u003eparser_(std::forward\u003cT\u003e(value), [\u0026](const auto\u0026 arg, const auto\u0026 head, auto\u0026\u0026 value) {\n                    return commander::tuple_visit_disjunction([\u0026](const auto\u0026 storage) {\n                        if (storage.match(arg, head))\n                            return storage.apply(value);\n                        return false;\n                    }, tup);\n                });\n            }\n            return *this;\n        }\n\n    private:\n        commander::basic_parser\u003cstd::string_view, std::string\u003e parser_;\n        std::pair\u003clength_type, length_type\u003e length_ = std::pair\u003clength_type, length_type\u003e(0, 0);\n        char fill_ = char(' ');\n};\n\nint main(int /*argc*/, const char ** /*argv*/)\n{\n    try {\n        rectangle_painter\u003cint\u003e rp;\n\n        // Let's set x to 12, y to 3 and use 'o' as filling character.\n        rp \u003c\u003c \"-x\" \u003c\u003c \"12\" \u003c\u003c \"-y=3\" \u003c\u003c \"--fill=o\";\n\n        // No, no, no - let's change x to 8, use 'x' as filling character and then execute.\n        rp \u003c\u003c \"--width\" \u003c\u003c 8 \u003c\u003c \"-f\" \u003c\u003c 'x' \u003c\u003c commander::exec\u003c\u003e();\n    }\n    catch(...) {\n        std::cout \u003c\u003c \"Whooops...\" \u003c\u003c '\\n';\n        return 1;\n    }\n}\n```\n\n### rectangle_painter expanded\nLet's expand our example and introduce a new option - invert.\n```cpp\n#include \u003carray\u003e\n#include \u003ciostream\u003e\n#include \u003cstring\u003e\n#include \u003cstring_view\u003e\n#include \u003cutility\u003e\n\n#include \u003cboost/lexical_cast.hpp\u003e\n#include \u003ccommander.hpp\u003e\n\ntemplate \u003ctypename Length\u003e\nclass rectangle_painter\n{\n    public:\n        using length_type = Length;\n\n        template \u003ctypename... Types\u003e\n        void operator ()(Types\u0026\u0026... values)\n        {\n            if constexpr (sizeof...(values) != 0)\n                ((*this) \u003c\u003c values \u003c\u003c ...);\n\n            this-\u003eparser_();\n            for (length_type y = 0; y \u003c this-\u003elength_.second; ++y) {\n                for (length_type x = 0; x \u003c this-\u003elength_.first; ++x)\n                    std::cout \u003c\u003c this-\u003efill_;\n                std::cout \u003c\u003c '\\n';\n            }\n            std::cout \u003c\u003c std::flush;\n        }\n\n        template \u003ctypename T\u003e\n        rectangle_painter\u003clength_type\u003e\u0026 operator \u003c\u003c(T\u0026\u0026 value)\n        {\n            if constexpr (commander::func::is_exec_v(value)) {\n                value(*this);\n            }\n            else {\n                auto tup = std::make_tuple(\n                    commander::make_empty_storage(\n                        commander::no_value,\n                        [](const std::string_view\u0026 header) { return commander::compare_disjunction(header, \"-x\", \"-w\", \"--width\"); },\n                        commander::make_applier(\n                            [this](const width_option\u003clength_type\u003e\u0026 xl) { this-\u003elength_.first = xl.length; return true; },\n                            [this](const length_type\u0026 xl) { this-\u003elength_.first = xl; return true; },\n                            [this](const std::string_view\u0026 xl) { this-\u003elength_.first = boost::lexical_cast\u003clength_type\u003e(xl); return true; }\n                        )\n                    ),\n                    commander::make_empty_storage(\n                        commander::no_value,\n                        [](const std::string_view\u0026 header) { return commander::compare_disjunction(header, \"-y\", \"-h\", \"--height\"); },\n                        commander::make_applier(\n                            [this](const height_option\u003clength_type\u003e\u0026 yl) { this-\u003elength_.second = yl.length; return true; },\n                            [this](const length_type\u0026 yl) { this-\u003elength_.second = yl; return true; },\n                            [this](const std::string_view\u0026 yl) { this-\u003elength_.second = boost::lexical_cast\u003clength_type\u003e(yl); return true; }\n                        )\n                    ),\n                    commander::make_empty_storage(\n                        commander::no_value,\n                        [](const std::string_view\u0026 header) { return commander::compare_disjunction(header, \"-f\", \"--fill\"); },\n                        commander::make_applier(\n                            [this](const fill_option\u0026 f) { this-\u003efill_ = f.character; return true; },\n                            [this](const char\u0026 f) { this-\u003efill_ = f; return true; },\n                            [this](const std::string_view\u0026 f) { this-\u003efill_ = boost::lexical_cast\u003cchar\u003e(f); return true; }\n                        )\n                    ),\n                    commander::make_empty_storage(\n                        commander::no_value,\n                        [](const std::string_view\u0026 header) { return commander::compare_disjunction(header, \"-i\", \"--inv\", \"--invert\"); },\n                        commander::make_applier(\n                            [this](const invert_option\u0026) { std::swap(this-\u003elength_.first, this-\u003elength_.second); return true; },\n                            commander::make_type_applier\u003ccommander::type_list\u003ccommander::no_value_t, commander::placeholder_t\u003e\u003e(\n                                [this]() { std::swap(this-\u003elength_.first, this-\u003elength_.second); return true; }\n                            ),\n                            [this](const bool\u0026 i) { if (i) std::swap(this-\u003elength_.first, this-\u003elength_.second); return true; },\n                            [this](const std::string_view\u0026 f) { if (boost::lexical_cast\u003cbool\u003e(f)) std::swap(this-\u003elength_.first, this-\u003elength_.second); return true; }\n                        )\n                    )\n                );\n\n                this-\u003eparser_(std::forward\u003cT\u003e(value), [\u0026](const auto\u0026 arg, const auto\u0026 head, auto\u0026\u0026 value) {\n                    return commander::tuple_visit_disjunction([\u0026](const auto\u0026 storage) {\n                        if (storage.match(arg, head))\n                            return storage.apply(value);\n                        return false;\n                    }, tup);\n                });\n            }\n            return *this;\n        }\n\n    private:\n        commander::basic_parser\u003cstd::string_view, std::string\u003e parser_;\n        std::pair\u003clength_type, length_type\u003e length_ = std::pair\u003clength_type, length_type\u003e(0, 0);\n        char fill_ = char(' ');\n};\n\nint main(int /*argc*/, const char ** /*argv*/)\n{\n    try {\n        rectangle_painter\u003cint\u003e rp;\n\n        // Let's set x to 8, y to 3, use 'x' as filling character and execute. Then let's invert, set y to 4 and execute again.\n        rp \u003c\u003c \"-x=8\" \u003c\u003c \"-y=3\" \u003c\u003c \"--fill=x\" \u003c\u003c commander::exec\u003c\u003e() \u003c\u003c \"-iy=4\" \u003c\u003c commander::exec\u003c\u003e();\n    }\n    catch(...) {\n        std::cout \u003c\u003c \"Whooops...\" \u003c\u003c '\\n';\n        return 1;\n    }\n}\n```\n\n### rectangle_painter program argument matching\nYou probably noticed that we use strings to match options. So the question is: can you use commander to parse program options?\n```cpp\n#include \u003calgorithm\u003e\n#include \u003carray\u003e\n#include \u003ciostream\u003e\n#include \u003cstring\u003e\n#include \u003cstring_view\u003e\n#include \u003cutility\u003e\n\n#include \u003cboost/lexical_cast.hpp\u003e\n#include \u003ccommander.hpp\u003e\n\ntemplate \u003ctypename Length\u003e\nclass rectangle_painter\n{\n    public:\n        using length_type = Length;\n\n        template \u003ctypename... Types\u003e\n        void operator ()(Types\u0026\u0026... values)\n        {\n            if constexpr (sizeof...(values) != 0)\n                ((*this) \u003c\u003c values \u003c\u003c ...);\n\n            this-\u003eparser_();\n            for (length_type y = 0; y \u003c this-\u003elength_.second; ++y) {\n                for (length_type x = 0; x \u003c this-\u003elength_.first; ++x)\n                    std::cout \u003c\u003c this-\u003efill_;\n                std::cout \u003c\u003c '\\n';\n            }\n            std::cout \u003c\u003c std::flush;\n        }\n\n        template \u003ctypename T\u003e\n        rectangle_painter\u003clength_type\u003e\u0026 operator \u003c\u003c(T\u0026\u0026 value)\n        {\n            if constexpr (commander::func::is_exec_v(value)) {\n                value(*this);\n            }\n            else {\n                auto tup = std::make_tuple(\n                    commander::make_empty_storage(\n                        commander::no_value,\n                        [](const std::string_view\u0026 header) { return commander::compare_disjunction(header, \"-x\", \"-w\", \"--width\"); },\n                        commander::make_applier(\n                            [this](const width_option\u003clength_type\u003e\u0026 xl) { this-\u003elength_.first = xl.length; return true; },\n                            [this](const length_type\u0026 xl) { this-\u003elength_.first = xl; return true; },\n                            [this](const std::string_view\u0026 xl) { this-\u003elength_.first = boost::lexical_cast\u003clength_type\u003e(xl); return true; }\n                        )\n                    ),\n                    commander::make_empty_storage(\n                        commander::no_value,\n                        [](const std::string_view\u0026 header) { return commander::compare_disjunction(header, \"-y\", \"-h\", \"--height\"); },\n                        commander::make_applier(\n                            [this](const height_option\u003clength_type\u003e\u0026 yl) { this-\u003elength_.second = yl.length; return true; },\n                            [this](const length_type\u0026 yl) { this-\u003elength_.second = yl; return true; },\n                            [this](const std::string_view\u0026 yl) { this-\u003elength_.second = boost::lexical_cast\u003clength_type\u003e(yl); return true; }\n                        )\n                    ),\n                    commander::make_empty_storage(\n                        commander::no_value,\n                        [](const std::string_view\u0026 header) { return commander::compare_disjunction(header, \"-f\", \"--fill\"); },\n                        commander::make_applier(\n                            [this](const fill_option\u0026 f) { this-\u003efill_ = f.character; return true; },\n                            [this](const char\u0026 f) { this-\u003efill_ = f; return true; },\n                            [this](const std::string_view\u0026 f) { this-\u003efill_ = boost::lexical_cast\u003cchar\u003e(f); return true; }\n                        )\n                    ),\n                    commander::make_empty_storage(\n                        commander::no_value,\n                        [](const std::string_view\u0026 header) { return commander::compare_disjunction(header, \"-i\", \"--inv\", \"--invert\"); },\n                        commander::make_applier(\n                            [this](const invert_option\u0026) { std::swap(this-\u003elength_.first, this-\u003elength_.second); return true; },\n                            commander::make_type_applier\u003ccommander::type_list\u003ccommander::no_value_t, commander::placeholder_t\u003e\u003e(\n                                [this]() { std::swap(this-\u003elength_.first, this-\u003elength_.second); return true; }\n                            ),\n                            [this](const bool\u0026 i) { if (i) std::swap(this-\u003elength_.first, this-\u003elength_.second); return true; },\n                            [this](const std::string_view\u0026 f) { if (boost::lexical_cast\u003cbool\u003e(f)) std::swap(this-\u003elength_.first, this-\u003elength_.second); return true; }\n                        )\n                    )\n                );\n\n                this-\u003eparser_(std::forward\u003cT\u003e(value), [\u0026](const auto\u0026 arg, const auto\u0026 head, auto\u0026\u0026 value) {\n                    return commander::tuple_visit_disjunction([\u0026](const auto\u0026 storage) {\n                        if (storage.match(arg, head))\n                            return storage.apply(value);\n                        return false;\n                    }, tup);\n                });\n            }\n            return *this;\n        }\n\n    private:\n        commander::basic_parser\u003cstd::string_view, std::string\u003e parser_;\n        std::pair\u003clength_type, length_type\u003e length_ = std::pair\u003clength_type, length_type\u003e(0, 0);\n        char fill_ = char(' ');\n};\n\nint main(int argc, const char ** argv)\n{\n    try {\n        rectangle_painter\u003cint\u003e rp;\n\n        std::for_each(argv + 1, argv + argc, [\u0026](const char* str) { rp \u003c\u003c str; });\n\n        rp();\n    }\n    catch(...) {\n        std::cout \u003c\u003c \"Whooops...\" \u003c\u003c '\\n';\n        return 1;\n    }\n}\n```\n\n### rectangle_painter zero overhead matching\nIt is worth notice that matching is based on strings, so it is some computational overhead. We can overcome this by introducing option types.\n\nThere are many ways to accomplish this. The example below uses storage metadata to keep a type_list.\n```cpp\n#include \u003carray\u003e\n#include \u003ciostream\u003e\n#include \u003cstring\u003e\n#include \u003cstring_view\u003e\n#include \u003cutility\u003e\n\n#include \u003cboost/lexical_cast.hpp\u003e\n#include \u003ccommander.hpp\u003e\n\ntemplate \u003ctypename Length\u003e\nstruct width_option { Length length; };\n\ntemplate \u003ctypename Length\u003e\nstruct height_option { Length length; };\n\nstruct fill_option { char character; };\n\nstruct invert_option {};\n\ntemplate \u003ctypename Length\u003e\nclass rectangle_painter\n{\n    public:\n        using length_type = Length;\n\n        template \u003ctypename... Types\u003e\n        void operator ()(Types\u0026\u0026... values)\n        {\n            if constexpr (sizeof...(values) != 0)\n                ((*this) \u003c\u003c values \u003c\u003c ...);\n\n            this-\u003eparser_();\n            for (length_type y = 0; y \u003c this-\u003elength_.second; ++y) {\n                for (length_type x = 0; x \u003c this-\u003elength_.first; ++x)\n                    std::cout \u003c\u003c this-\u003efill_;\n                std::cout \u003c\u003c '\\n';\n            }\n            std::cout \u003c\u003c std::flush;\n        }\n\n        template \u003ctypename T\u003e\n        rectangle_painter\u003clength_type\u003e\u0026 operator \u003c\u003c(T\u0026\u0026 value)\n        {\n            if constexpr (commander::func::is_exec_v(value)) {\n                value(*this);\n            }\n            else {\n                auto tup = std::make_tuple(\n                    commander::make_empty_storage(\n                        commander::type_list\u003cwidth_option\u003clength_type\u003e\u003e{},\n                        [](const std::string_view\u0026 header) { return commander::compare_disjunction(header, \"-x\", \"-w\", \"--width\"); },\n                        commander::make_applier(\n                            [this](const width_option\u003clength_type\u003e\u0026 xl) { this-\u003elength_.first = xl.length; return true; },\n                            [this](const length_type\u0026 xl) { this-\u003elength_.first = xl; return true; },\n                            [this](const std::string_view\u0026 xl) { this-\u003elength_.first = boost::lexical_cast\u003clength_type\u003e(xl); return true; }\n                        )\n                    ),\n                    commander::make_empty_storage(\n                        commander::type_list\u003cheight_option\u003clength_type\u003e\u003e{},\n                        [](const std::string_view\u0026 header) { return commander::compare_disjunction(header, \"-y\", \"-h\", \"--height\"); },\n                        commander::make_applier(\n                            [this](const height_option\u003clength_type\u003e\u0026 yl) { this-\u003elength_.second = yl.length; return true; },\n                            [this](const length_type\u0026 yl) { this-\u003elength_.second = yl; return true; },\n                            [this](const std::string_view\u0026 yl) { this-\u003elength_.second = boost::lexical_cast\u003clength_type\u003e(yl); return true; }\n                        )\n                    ),\n                    commander::make_empty_storage(\n                        commander::type_list\u003cfill_option\u003e{},\n                        [](const std::string_view\u0026 header) { return commander::compare_disjunction(header, \"-f\", \"--fill\"); },\n                        commander::make_applier(\n                            [this](const fill_option\u0026 f) { this-\u003efill_ = f.character; return true; },\n                            [this](const char\u0026 f) { this-\u003efill_ = f; return true; },\n                            [this](const std::string_view\u0026 f) { this-\u003efill_ = boost::lexical_cast\u003cchar\u003e(f); return true; }\n                        )\n                    ),\n                    commander::make_empty_storage(\n                        commander::type_list\u003cinvert_option\u003e{},\n                        [](const std::string_view\u0026 header) { return commander::compare_disjunction(header, \"-i\", \"--inv\", \"--invert\"); },\n                        commander::make_applier(\n                            [this](const invert_option\u0026) { std::swap(this-\u003elength_.first, this-\u003elength_.second); return true; },\n                            commander::make_type_applier\u003ccommander::type_list\u003ccommander::no_value_t, commander::placeholder_t\u003e\u003e(\n                                [this]() { std::swap(this-\u003elength_.first, this-\u003elength_.second); return true; }\n                            ),\n                            [this](const bool\u0026 i) { if (i) std::swap(this-\u003elength_.first, this-\u003elength_.second); return true; },\n                            [this](const std::string_view\u0026 f) { if (boost::lexical_cast\u003cbool\u003e(f)) std::swap(this-\u003elength_.first, this-\u003elength_.second); return true; }\n                        )\n                    )\n                );\n\n                auto type_check = [\u0026](const auto\u0026 storage) {\n                    if constexpr (commander::tl::index_of_v\u003cstd::decay_t\u003cdecltype(storage.metadata())\u003e, std::decay_t\u003cT\u003e\u003e != commander::tl::npos) {\n                        storage.apply(value);\n                        return true;\n                    }\n                    return false;\n                };\n\n                if (!commander::tuple_visit_disjunction(type_check, tup)) {\n                    this-\u003eparser_(std::forward\u003cT\u003e(value), [\u0026](const auto\u0026 arg, const auto\u0026 head, auto\u0026\u0026 value) {\n                        return commander::tuple_visit_disjunction([\u0026](const auto\u0026 storage) {\n                            if (storage.match(arg, head))\n                                return storage.apply(value);\n                            return false;\n                        }, tup);\n                    });\n                }\n            }\n            return *this;\n        }\n\n    private:\n        commander::basic_parser\u003cstd::string_view, std::string\u003e parser_;\n        std::pair\u003clength_type, length_type\u003e length_ = std::pair\u003clength_type, length_type\u003e(0, 0);\n        char fill_ = char(' ');\n};\n\nint main(int /*argc*/, const char ** /*argv*/)\n{\n    try {\n        rectangle_painter\u003cint\u003e rp;\n\n        // Let's set x to 8, y to 3, use 'x' as filling character and execute.\n        rp \u003c\u003c width_option\u003cint\u003e{8} \u003c\u003c height_option\u003cint\u003e{3} \u003c\u003c fill_option{'x'} \u003c\u003c commander::exec\u003c\u003e();\n    }\n    catch(...) {\n        std::cout \u003c\u003c \"Whooops...\" \u003c\u003c '\\n';\n        return 1;\n    }\n}\n```\n\n## The command design pattern with the commander library\n\u003e Creation of this section is still in progress.\n\n## Used third-party tools and libraries\n\nThe commander itself is a header-only library licensed under the BSL license. Note, that you do not need any third-party software to use it!\n\n- [Boost C++ Libraries](http://www.boost.org) - for the unit tests\n- [Cmake](https://cmake.org) - for build automation\n\n## License\n\nThe commander library is open-source software licensed under the [Boost Software License 1.0](https://opensource.org/licenses/bsl1.0).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdaishe%2Fcommander","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdaishe%2Fcommander","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdaishe%2Fcommander/lists"}