{"id":13441033,"url":"https://github.com/p-ranav/structopt","last_synced_at":"2025-04-08T06:36:31.670Z","repository":{"id":39707691,"uuid":"286767036","full_name":"p-ranav/structopt","owner":"p-ranav","description":"Parse command line arguments by defining a struct","archived":false,"fork":false,"pushed_at":"2024-10-27T15:29:04.000Z","size":664,"stargazers_count":489,"open_issues_count":6,"forks_count":27,"subscribers_count":12,"default_branch":"master","last_synced_at":"2025-04-01T05:38:14.544Z","etag":null,"topics":["argparse","argument-parser","arguments","clap","command-line","cpp17","cross-platform","header-library","header-only","library","lightweight","magic-enum","mit-license","modern-cpp","reflection","single-header-lib","structopt","type-safe","type-safety","visit-struct-library"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/p-ranav.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","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":"2020-08-11T14:32:51.000Z","updated_at":"2025-03-29T09:14:18.000Z","dependencies_parsed_at":"2024-11-21T20:16:27.309Z","dependency_job_id":null,"html_url":"https://github.com/p-ranav/structopt","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/p-ranav%2Fstructopt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/p-ranav%2Fstructopt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/p-ranav%2Fstructopt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/p-ranav%2Fstructopt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/p-ranav","download_url":"https://codeload.github.com/p-ranav/structopt/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247792892,"owners_count":20996891,"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":["argparse","argument-parser","arguments","clap","command-line","cpp17","cross-platform","header-library","header-only","library","lightweight","magic-enum","mit-license","modern-cpp","reflection","single-header-lib","structopt","type-safe","type-safety","visit-struct-library"],"created_at":"2024-07-31T03:01:29.120Z","updated_at":"2025-04-08T06:36:31.626Z","avatar_url":"https://github.com/p-ranav.png","language":"C++","funding_links":[],"categories":["C++","Argument Parsers"],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg height=\"70\" src=\"img/logo.png\"/\u003e  \n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  Parse command line arguments by defining a struct\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/p-ranav/structopt/releases\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/release/p-ranav/structopt.svg\" alt=\"ci status\"/\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://conan.io/center/structopt/0.1.2\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Conan-package-blueviolet\" alt=\"conan package\"/\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://travis-ci.com/p-ranav/structopt\"\u003e\n    \u003cimg src=\"https://travis-ci.com/p-ranav/structopt.svg?branch=master\" alt=\"ci status\"/\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://ci.appveyor.com/project/p-ranav/structopt/branch/master\"\u003e\n    \u003cimg src=\"https://ci.appveyor.com/api/projects/status/fyufe5f11mhahwq9/branch/master?svg=true\" alt=\"ci status\"/\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://www.codacy.com/manual/p-ranav/structopt?utm_source=github.com\u0026amp;utm_medium=referral\u0026amp;utm_content=p-ranav/structopt\u0026amp;utm_campaign=Badge_Grade\"\u003e\n    \u003cimg src=\"https://app.codacy.com/project/badge/Grade/e6e76a680e61445a90616d27cb69b927\" alt=\"codacy\"/\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://en.wikipedia.org/wiki/C%2B%2B17\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/C%2B%2B-17-blue.svg\" alt=\"standard\"/\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/p-ranav/tabulate/blob/master/LICENSE\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/License-MIT-yellow.svg\" alt=\"license\"/\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n## Quick Start\n\n```cpp\n#include \u003cstructopt/app.hpp\u003e\n\nstruct Options {\n   // positional argument\n   //   e.g., ./main \u003cfile\u003e\n   std::string config_file;\n\n   // optional argument\n   //   e.g., -b \"192.168.5.3\"\n   //   e.g., --bind_address \"192.168.5.3\"\n   //\n   // options can be delimited with `=` or `:`\n   // note: single dash (`-`) is enough for short \u0026 long option\n   //   e.g., -bind_address=localhost\n   //   e.g., -b:192.168.5.3\n   //\n   // the long option can also be provided in kebab case:\n   //   e.g., --bind-address 192.168.5.3\n   std::optional\u003cstd::string\u003e bind_address;\n \n   // flag argument\n   // Use `std::optional\u003cbool\u003e` and provide a default value. \n   //   e.g., -v\n   //   e.g., --verbose\n   //   e.g., -verbose\n   std::optional\u003cbool\u003e verbose = false;\n\n   // directly define and use enum classes to limit user choice\n   //   e.g., --log-level debug\n   //   e.g., -l error\n   enum class LogLevel { debug, info, warn, error, critical };\n   std::optional\u003cLogLevel\u003e log_level = LogLevel::info;\n\n   // pair argument\n   // e.g., -u \u003cfirst\u003e \u003csecond\u003e\n   // e.g., --user \u003cfirst\u003e \u003csecond\u003e\n   std::optional\u003cstd::pair\u003cstd::string, std::string\u003e\u003e user;\n\n   // use containers like std::vector\n   // to collect \"remaining arguments\" into a list\n   std::vector\u003cstd::string\u003e files;\n};\nSTRUCTOPT(Options, config_file, bind_address, verbose, log_level, user, files);\n```\n\nCreate a `structopt::app` and parse the command line arguments into the `Options` struct:\n\n```cpp\nint main(int argc, char *argv[]) {\n\n  try {\n  \n    // Line of code that does all the work:\n    auto options = structopt::app(\"my_app\").parse\u003cOptions\u003e(argc, argv);\n\n    // Print out parsed arguments:\n\n    // std::cout \u003c\u003c \"config_file  = \" \u003c\u003c options.config_file \u003c\u003c \"\\n\";\n    // std::cout \u003c\u003c \"bind_address = \" \u003c\u003c options.bind_address.value_or(\"not provided\") \u003c\u003c \"\\n\";\n    // std::cout \u003c\u003c \"verbose      = \" \u003c\u003c std::boolalpha \u003c\u003c options.verbose.value() \u003c\u003c \"\\n\";\n    // ...\n\n  } catch (structopt::exception\u0026 e) {\n    std::cout \u003c\u003c e.what() \u003c\u003c \"\\n\";\n    std::cout \u003c\u003c e.help();\n  }\n}\n```\n\nNow let's pass some arguments to this program:\n\n```console\nfoo@bar:~$ ./main config.csv file5.csv file6.json\nconfig_file  = config.csv\nbind_address = not provided\nverbose      = false\nlog_level    = 1\nuser         = not provided\nfiles        = { file5.csv file6.json }\n\nfoo@bar:~$ ./main config.csv --bind-address localhost:9000 -v -log-level error file1.txt file2.txt\nconfig_file  = config.csv\nbind_address = localhost:9000\nverbose      = true\nlog_level    = 3\nuser         = not provided\nfiles        = { file1.txt file2.txt }\n\nfoo@bar:~$ ./main config_2.csv --bind-address 192.168.7.3 -log-level debug file1.txt file3.txt file4.txt --user \"John Doe\" \"john.doe@foo.com\"\nconfig_file  = config_2.csv\nbind_address = 192.168.7.3\nverbose      = false\nlog_level    = 0\nuser         = John Doe\u003cjohn.doe@foo.com\u003e\nfiles        = { file1.txt file3.txt file4.txt }\n```\n\n## Table of Contents\n\n*    [Getting Started](#getting-started)\n     *    [Positional Arguments](#positional-arguments)\n     *    [Optional Arguments](#optional-arguments)\n          *    [Double dash (`--`) Argument](#double-dash----argument)\n     *    [Flag Arguments](#flag-arguments)\n     *    [Enum Class Arguments (Choices)](#enum-class-arguments)\n     *    [Tuple Arguments](#tuple-arguments)\n     *    [Vector Arguments](#vector-arguments)\n     *    [Compound Arguments](#compound-arguments)\n     *    [Parsing Numbers](#parsing-numbers)\n          *    [Integer Literals](#integer-literals)\n          *    [Floating point Literals](#floating-point-literals)\n     *    [Nested Structures (Sub-commands)](#nested-structures)\n     *    [Sub-Commands, Vector Arguments, and Delimited Positional Arguments](#sub-commands-vector-arguments-and-delimited-positional-arguments)\n     *    [Printing Help](#printing-help)\n     *    [Printing CUSTOM Help](#printing-custom-help)\n*    [Building Samples and Tests](#building-samples-and-tests)\n*    [Compiler Compatibility](#compiler-compatibility)\n*    [Generating Single Header](#generating-single-header)\n*    [Contributing](#contributing)\n*    [License](#license)\n\n## Getting Started \n\n`structopt` is a header-only library. Just add `include/` to your _include_directories_ and you should be good to go. A single header file version is also available in `single_include/`.\n\n### Positional Arguments\n\nHere's an example of two positional arguments: `input_file` and `output_file`. `input_file` is expected to be the first argument and `output_file` is expected to be the second argument\n\n```cpp\n#include \u003cstructopt/app.hpp\u003e\n\nstruct FileOptions {\n  // Positional arguments\n  // ./main \u003cinput_file\u003e \u003coutput_file\u003e\n  std::string input_file;\n  std::string output_file;\n};\nSTRUCTOPT(FileOptions, input_file, output_file);\n\n\n\nint main(int argc, char *argv[]) {\n\n  try {\n    auto options = structopt::app(\"my_app\").parse\u003cFileOptions\u003e(argc, argv);\n\n    // Print parsed arguments:\n    std::cout \u003c\u003c \"\\nInput file  : \" \u003c\u003c options.input_file \u003c\u003c \"\\n\";\n    std::cout \u003c\u003c \"Output file : \" \u003c\u003c options.output_file \u003c\u003c \"\\n\";\n\n  } catch (structopt::exception\u0026 e) {\n    std::cout \u003c\u003c e.what() \u003c\u003c \"\\n\";\n    std::cout \u003c\u003c e.help();\n  }\n}\n```\n\n```console\nfoo@bar:~$ ./main foo.txt bar.csv\n\nInput file  : foo.txt\nOutput file : bar.csv\n\nfoo@bar:~$ ./main foo.csv\nError: expected value for positional argument `output_file`.\n\nUSAGE: ./my_app input_file output_file\n\nARGS:\n    input_file\n    output_file\n```\n\n### Optional Arguments\n\nNow, let's look at optional arguments. To configure an optional argument, use `std::optional` in the options struct like below.\n\n```cpp\n#include \u003cstructopt/app.hpp\u003e\n\nstruct GccOptions {\n  // language standard\n  // e.g., -std=c++17\n  // e.g., --std c++20\n  std::optional\u003cstd::string\u003e std = \"c++11\";\n\n  // verbosity enabled with `-v` or `--verbose`\n  // or `-verbose`\n  std::optional\u003cbool\u003e verbose = false;\n\n  // enable all warnings with `-Wall`\n  std::optional\u003cbool\u003e Wall = false;\n\n  // produce only the compiled code\n  // e.g., gcc -C main.c\n  std::optional\u003cbool\u003e Compile = false;\n\n  // produce output with `-o \u003cexec_name\u003e`\n  std::optional\u003cstd::string\u003e output = \"a.out\";\n\n  std::string input_file;\n};\nSTRUCTOPT(GccOptions, std, verbose, Wall, Compile, output, input_file);\n\n\nint main(int argc, char *argv[]) {\n  try {\n    auto options = structopt::app(\"gcc\").parse\u003cGccOptions\u003e(argc, argv);\n\n    // Print parsed arguments\n\n    std::cout \u003c\u003c \"std        : \" \u003c\u003c options.std.value() \u003c\u003c \"\\n\";\n    std::cout \u003c\u003c \"verbose    : \" \u003c\u003c std::boolalpha \u003c\u003c options.verbose.value() \u003c\u003c \"\\n\";\n    std::cout \u003c\u003c \"Wall       : \" \u003c\u003c std::boolalpha \u003c\u003c options.Wall.value() \u003c\u003c \"\\n\";\n    std::cout \u003c\u003c \"Compile    : \" \u003c\u003c std::boolalpha \u003c\u003c options.Compile.value() \u003c\u003c \"\\n\";\n    std::cout \u003c\u003c \"Output     : \" \u003c\u003c options.output.value() \u003c\u003c \"\\n\";\n    std::cout \u003c\u003c \"Input file : \" \u003c\u003c options.input_file \u003c\u003c \"\\n\";\n  } catch (structopt::exception \u0026e) {\n    std::cout \u003c\u003c e.what() \u003c\u003c \"\\n\";\n    std::cout \u003c\u003c e.help();\n  }\n}\n```\n\n***NOTE*** `structopt` supports two option delimiters, `=` and `:` for optional arguments. This is meaningful and commonly used in single-valued optional arguments, e.g., `--std=c++17`.\n\n```console\nfoo@bar:~$ ./main -C main.cpp\nstd        : c++11\nverbose    : false\nWall       : false\nCompile    : true\nOutput     : a.out\nInput file : main.cpp\n\nfoo@bar:~$ ./main -std=c++17 -o main main.cpp\nstd        : c++17\nverbose    : false\nWall       : false\nCompile    : false\nOutput     : main\nInput file : main.cpp\n\nfoo@bar:~$ ./main main.cpp -v -std:c++14 --output:main -Wall\nstd        : c++14\nverbose    : true\nWall       : true\nCompile    : false\nOutput     : main\nInput file : main.cpp\n```\n\n***NOTE*** In summary, for a field in your struct named `bind_address`, the following are all legal ways to provide a value:\n\n* Short form:\n  * `-b \u003cvalue\u003e`\n* Long form:\n  * `--bind_address \u003cvalue\u003e`\n  * `-bind_address \u003cvalue\u003e`\n* Kebab case:\n  * `--bind-address \u003cvalue\u003e`\n  * `-bind-address \u003cvalue\u003e`\n* Equal (`'='`) option delimiter\n  * `-b=\u003cvalue\u003e`\n  * `--bind_address=\u003cvalue\u003e`\n  * `-bind_address=\u003cvalue\u003e`\n  * `--bind-address=\u003cvalue\u003e`\n  * `-bind-address=\u003cvalue\u003e`\n* Colon `':'` option delimiter\n  * `-b:\u003cvalue\u003e`\n  * `--bind_address:\u003cvalue\u003e`\n  * `-bind_address:\u003cvalue\u003e`\n  * `--bind-address:\u003cvalue\u003e`\n  * `-bind-address:\u003cvalue\u003e`\n\n#### Double dash (`--`) Argument\n\nA double dash (`--`) is used in most bash built-in commands and many other commands to signify the end of command options, after which only positional parameters are accepted.\n\nExample use: lets say you want to `grep` a file for the string `-v` - normally `-v` will be considered the option to reverse the matching meaning (only show lines that do not match), but with `--` you can `grep` for string `-v` like this:\n\n```cpp\n#include \u003cstructopt/app.hpp\u003e\n\nstruct GrepOptions {\n  // reverse the matching\n  // enable with `-v`\n  std::optional\u003cbool\u003e v = false;\n  \n  // positional arguments\n  std::string search;\n  std::string pathspec;\n};\nSTRUCTOPT(GrepOptions, v, search, pathspec);\n\n\n\nint main(int argc, char *argv[]) {\n\n  try {\n    auto options = structopt::app(\"my_app\").parse\u003cGrepOptions\u003e(argc, argv);\n\n    if (options.v == true) {\n      std::cout \u003c\u003c \"`-v` provided - Matching is now reversed\\n\";\n    }\n\n    std::cout \u003c\u003c \"Search   : \" \u003c\u003c options.search \u003c\u003c \"\\n\";\n    std::cout \u003c\u003c \"Pathspec : \" \u003c\u003c options.pathspec \u003c\u003c \"\\n\";\n  }\n  catch (structopt::exception\u0026 e) {\n    std::cout \u003c\u003c e.what();\n    std::cout \u003c\u003c e.help();\n  }\n\n}\n```\n\n```console\nfoo@bar:~$ ./main -v foo bar.txt\n`-v` provided - Matching is now reversed\nSearch   : foo\nPathspec : bar.txt\n\nfoo@bar:~$ ./main -- -v bar.txt\nSearch   : -v\nPathspec : bar.txt\n```\n\n### Flag Arguments\n\nFlag arguments are `std::optional\u003cbool\u003e` with a default value. \n\n***NOTE*** The default value here is important. It is not a flag if a default value isn't provided. It will simply be an optional argument. \n\n***NOTE*** If `--verbose` is a flag argument with a default value of `false`, then providing the argument will set it to `true`. If `--verbose` does not have a default value, then `structopt` will expect the user to provide a value, e.g., `--verbose true`. \n\n```cpp\n#include \u003cstructopt/app.hpp\u003e\n\nstruct Options {\n  // verbosity flag\n  // -v, --verbose\n  // remember to provide a default value\n  std::optional\u003cbool\u003e verbose = false;\n};\nSTRUCTOPT(Options, verbose);\n\n\n\nint main(int argc, char *argv[]) {\n  auto options = structopt::app(\"my_app\").parse\u003cOptions\u003e(argc, argv);\n\n  if (options.verbose == true) {\n    std::cout \u003c\u003c \"Verbosity enabled\\n\";\n  }\n}\n```\n\n```console\nfoo@bar:~$ ./main\n\nfoo@bar:~$ ./main -v\nVerbosity enabled\n\nfoo@bar:~$ ./main --verbose\nVerbosity enabled\n```\n\n### Enum Class Arguments\n\nThanks to [magic_enum](https://github.com/Neargye/magic_enum), `structopt` supports enum classes. You can use an enum classes to ask the user to provide a value given a choice of values, restricting the possible set of allowed input arguments.\n\n```cpp\n#include \u003cstructopt/app.hpp\u003e\n\nstruct StyleOptions {\n  enum class Color {red, green, blue};\n\n  // e.g., `--color red`\n  std::optional\u003cColor\u003e color = Color::red;\n};\nSTRUCTOPT(StyleOptions, color);\n\n\n\nint main(int argc, char *argv[]) {\n\n  try {\n    auto options = structopt::app(\"my_app\").parse\u003cStyleOptions\u003e(argc, argv);\n\n    // Use parsed argument `options.color`\n\n    if (options.color == StyleOptions::Color::red) {\n        std::cout \u003c\u003c \"#ff0000\\n\";\n    }\n    else if (options.color == StyleOptions::Color::blue) {\n        std::cout \u003c\u003c \"#0000ff\\n\";\n    }\n    else if (options.color == StyleOptions::Color::green) {\n        std::cout \u003c\u003c \"#00ff00\\n\";\n    }\n\n  } catch (structopt::exception\u0026 e) {\n    std::cout \u003c\u003c e.what() \u003c\u003c \"\\n\";\n    std::cout \u003c\u003c e.help();\n  }\n}\n```\n\n```console\nfoo@bar:~$ ./main --color red\n#ff0000\n\nfoo@bar:~$ ./main -c blue\n#0000ff\n\nfoo@bar:~$ ./main --color green\n#00ff00\n\nfoo@bar:~$ ./main -c black\nError: unexpected input `black` provided for enum argument `color`. Allowed values are {red, green, blue}\n\nUSAGE: ./my_app [OPTIONS]\n\nOPTIONS:\n    -c, --color \u003ccolor\u003e\n```\n\n### Tuple Arguments\n\nNow that we've looked at enum class support, let's build a simple calculator. In this sample, we will use an `std::tuple` to pack all the arguments to the calculator:\n\n```cpp\n#include \u003cstructopt/app.hpp\u003e\n\nstruct CalculatorOptions {\n\n  // types of operations supported\n  enum class operation { add, subtract, multiply, divide };\n\n  // single tuple positional argument\n  std::tuple\u003coperation, int, int\u003e input;\n\n};\nSTRUCTOPT(CalculatorOptions, input);\n\n\n\nint main(int argc, char *argv[]) {\n\n  try {\n    auto options = structopt::app(\"my_app\").parse\u003cCalculatorOptions\u003e(argc, argv);\n\n    auto op = std::get\u003c0\u003e(options.input);\n    auto lhs = std::get\u003c1\u003e(options.input);\n    auto rhs = std::get\u003c2\u003e(options.input);\n    switch(op)\n    {\n        case CalculatorOptions::operation::add:\n            std::cout \u003c\u003c lhs + rhs \u003c\u003c \"\\n\";\n            break;\n        case CalculatorOptions::operation::subtract:\n            std::cout \u003c\u003c lhs - rhs \u003c\u003c \"\\n\";\n            break;\n        case CalculatorOptions::operation::multiply:\n            std::cout \u003c\u003c lhs * rhs \u003c\u003c \"\\n\";\n            break;\n        case CalculatorOptions::operation::divide:\n            std::cout \u003c\u003c lhs / rhs \u003c\u003c \"\\n\";\n            break;\n    }\n  }\n  catch (structopt::exception\u0026 e) {\n    std::cout \u003c\u003c e.what();\n    std::cout \u003c\u003c e.help();\n  }\n\n}\n```\n\n```console\nfoo@bar:~$ ./main add 1 2\n3\n\nfoo@bar:~$ ./main subtract 5 9\n-4\n\nfoo@bar:~$ ./main multiply 16 5\n80\n\nfoo@bar:~$ ./main divide 1331 11\n121\n\nfoo@bar:~$ ./main add 5\nError: failed to correctly parse tuple `input`. Expected 3 arguments, 2 provided.\n\nUSAGE: my_app input\n\nARGS:\n    input\n```\n\n### Vector Arguments\n\n`structopt` supports gathering \"remaining\" arguments at the end of the command, e.g., for use in a compiler:\n\n```bash\n$ compiler file1 file2 file3\n```\n\nDo this by using an `std::vector\u003cT\u003e` (or other STL containers with `.push_back()`, e.g, `std::deque` or `std::list`).\n\n***NOTE*** Vector arguments have a cardinality of `0..*`, i.e., zero or more arguments. Unlike array types, you can provide zero arguments to a vector and `structopt` will (try to) not complain.\n\n```cpp\n#include \u003cstructopt/app.hpp\u003e\n\nstruct CompilerOptions {\n  // Language standard\n  // e.g., --std c++17\n  std::optional\u003cstd::string\u003e std;\n\n  // remaining arguments\n  // e.g., ./compiler file1 file2 file3\n  std::vector\u003cstd::string\u003e files{};\n};\nSTRUCTOPT(CompilerOptions, std, files);\n\n\n\nint main(int argc, char *argv[]) {\n  try {\n    auto options = structopt::app(\"my_app\").parse\u003cCompilerOptions\u003e(argc, argv);\n\n    std::cout \u003c\u003c \"Standard : \" \u003c\u003c options.std.value_or(\"not provided\") \u003c\u003c \"\\n\";\n    std::cout \u003c\u003c \"Files    : { \";\n    std::copy(options.files.begin(), options.files.end(),\n              std::ostream_iterator\u003cstd::string\u003e(std::cout, \" \"));\n    std::cout \u003c\u003c \"}\" \u003c\u003c std::endl;\n  } catch (structopt::exception \u0026e) {\n    std::cout \u003c\u003c e.what() \u003c\u003c \"\\n\";\n    std::cout \u003c\u003c e.help();\n  }\n}\n```\n\n***NOTE*** Notice below that the act of gathering remaining arguments is arrested as soon as an optional argument is detected. See the output of `./main file1.cpp file2.cpp --std c++17` below. Notice that `--std=c++17` is not part of the vector. This is because `--std` is a valid optional argument.\n\n```console\nfoo@bar:~$ ./main\nStandard : not provided\nFiles    : { }\n\nfoo@bar:~$ ./main file1.cpp file2.cpp\nStandard : not provided\nFiles    : { file1.cpp file2.cpp }\n\nfoo@bar:~$ ./main file1.cpp file2.cpp --std=c++17\nStandard : c++17\nFiles    : { file1.cpp file2.cpp }\n\nfoo@bar:~$ ./main --std:c++20 file1.cpp file2.cpp\nStandard : c++20\nFiles    : { file1.cpp file2.cpp }\n```\n\n### Compound Arguments\n\nCompound arguments are optional arguments that are combined and provided as a single argument. Example: `ps -aux`\n\n```cpp\n#include \u003cstructopt/app.hpp\u003e\n\nstruct Options {\n  // Flag arguments\n  std::optional\u003cbool\u003e a = false;\n  std::optional\u003cbool\u003e b = false;\n\n  // Optional argument\n  // e.g., -c 1.1 2.2\n  std::optional\u003cstd::array\u003cfloat, 2\u003e\u003e c = {};\n};\nSTRUCTOPT(Options, a, b, c);\n\n\n\nint main(int argc, char *argv[]) {\n  try {\n    auto options = structopt::app(\"my_app\").parse\u003cOptions\u003e(argc, argv);\n\n    // Print parsed arguments:\n\n    std::cout \u003c\u003c std::boolalpha \u003c\u003c \"a = \" \u003c\u003c options.a.value()\n              \u003c\u003c \", b = \" \u003c\u003c options.b.value() \u003c\u003c \"\\n\";\n    if (options.c.has_value()) {\n      std::cout \u003c\u003c \"c = [\" \u003c\u003c options.c.value()[0] \u003c\u003c \", \" \u003c\u003c options.c.value()[1]\n                \u003c\u003c \"]\\n\";\n    }\n  } catch (structopt::exception \u0026e) {\n    std::cout \u003c\u003c e.what() \u003c\u003c \"\\n\";\n    std::cout \u003c\u003c e.help();\n  }\n}\n```\n\n```console\nfoo@bar:~$ ./main -ac 3.14 2.718\na = true, b = false\nc = [3.14, 2.718]\n\nfoo@bar:~$ ./main -ba\na = true, b = true\n\nfoo@bar:~$ ./main -c 1.5 3.0 -ab\na = true, b = true\nc = [1.5, 3]\n```\n\n### Parsing Numbers\n\n#### Integer Literals\n\n`structopt` supports parsing integer literals including hexadecimal, octal, and binary notation. \n\n```cpp\n#include \u003cstructopt/app.hpp\u003e\n\nstruct IntegerLiterals {\n  std::vector\u003cint\u003e numbers;\n};\nSTRUCTOPT(IntegerLiterals, numbers);\n\nint main(int argc, char *argv[]) {\n  try {\n    auto options = structopt::app(\"my_app\").parse\u003cIntegerLiterals\u003e(argc, argv);\n\n    for (auto \u0026n : options.numbers)\n      std::cout \u003c\u003c n \u003c\u003c \"\\n\";\n  } catch (structopt::exception \u0026e) {\n    std::cout \u003c\u003c e.what() \u003c\u003c \"\\n\";\n    std::cout \u003c\u003c e.help();\n  }\n}\n```\n\n```console\nfoo@bar:~$ ./main 1 0x5B 071 0b0101 -35 +98\n1\n91\n57\n5\n-35\n98\n```\n\n#### Floating point Literals\n\nAs for floating point numbers, `structopt` supports parsing scientific notation (e/E-notation):\n\n```cpp\n#include \u003cstructopt/app.hpp\u003e\n\nstruct FloatLiterals {\n  std::vector\u003cfloat\u003e numbers;\n};\nSTRUCTOPT(FloatLiterals, numbers);\n\nint main(int argc, char *argv[]) {\n  try {\n    auto options = structopt::app(\"my_app\").parse\u003cFloatLiterals\u003e(argc, argv);\n\n    for (auto \u0026n : options.numbers)\n      std::cout \u003c\u003c n \u003c\u003c \"\\n\";\n  } catch (structopt::exception \u0026e) {\n    std::cout \u003c\u003c e.what() \u003c\u003c \"\\n\";\n    std::cout \u003c\u003c e.help();\n  }\n}\n```\n\n```console\nfoo@bar:~$ ./main -3.15 +2.717 2E-4 0.1e2 .5 -.3 +5.999\n-3.15\n2.717\n0.0002\n10\n0.5\n-0.3\n5.999\n```\n\n### Nested Structures\n\nWith `structopt`, you can define sub-commands, e.g., `git init args` or `git config [flags] args` using nested structures. \n\n* Simply create a nested structure that inherits from `structopt::sub_command`\n* You can use `\u003cnested_struct_object\u003e.has_value()` to check if it has been invoked. \n\nThe following program support two sub-commands: `config` and `init`:\n\n```cpp\n#include \u003cstructopt/app.hpp\u003e\n\nstruct Git {\n  // Subcommand: git config\n  struct Config : structopt::sub_command {\n    // flag argument `--global`\n    std::optional\u003cbool\u003e global = false;\n\n    // key-value pair, e.g., `user.name \"John Doe\"`\n    std::array\u003cstd::string, 2\u003e name_value_pair{};\n  };\n  Config config;\n\n  // Subcommand: git init\n  struct Init : structopt::sub_command {\n\n    // required argument\n    // repository name\n    std::string name;\n  };\n  Init init;\n};\nSTRUCTOPT(Git::Config, global, name_value_pair);\nSTRUCTOPT(Git::Init, name);\nSTRUCTOPT(Git, config, init);\n\n\n\nint main(int argc, char *argv[]) {\n\n\n  try {\n    auto options = structopt::app(\"my_app\").parse\u003cGit\u003e(argc, argv);\n\n    if (options.config.has_value()) {\n      // config was invoked\n      std::cout \u003c\u003c \"You invoked `git config`:\\n\";\n      std::cout \u003c\u003c \"Global : \" \u003c\u003c std::boolalpha \u003c\u003c options.config.global.value() \u003c\u003c \"\\n\";\n      std::cout \u003c\u003c \"Input  : (\" \u003c\u003c options.config.name_value_pair[0] \u003c\u003c \", \" \u003c\u003c options.config.name_value_pair[1] \u003c\u003c \")\\n\";\n    }\n    else if (options.init.has_value()) {\n      // init was invoked\n      std::cout \u003c\u003c \"You invoked `git init`:\\n\";\n      std::cout \u003c\u003c \"Repository name : \" \u003c\u003c options.init.name \u003c\u003c \"\\n\";\n    }\n\n\n  } catch (structopt::exception\u0026 e) {\n    std::cout \u003c\u003c e.what() \u003c\u003c \"\\n\";\n    std::cout \u003c\u003c e.help();\n  }\n}\n```\n\n```console\nfoo@bar:~$ ./main config user.email \"john.doe@foo.com\"\nYou invoked `git config`:\nGlobal : false\nInput  : (user.email, john.doe@foo.com)\n\nfoo@bar:~$ ./main config user.name \"John Doe\" --global\nYou invoked `git config`:\nGlobal : true\nInput  : (user.name, John Doe)\n\nfoo@bar:~$ ./main init my_repo\nYou invoked `git init`:\nRepository name : my_repo\n\n\n\nfoo@bar:~$ ./main -h\n\nUSAGE: my_app [OPTIONS] [SUBCOMMANDS]\n\nOPTIONS:\n    -h, --help \u003chelp\u003e\n    -v, --version \u003cversion\u003e\n\nSUBCOMMANDS:\n    config\n    init\n\n\n\n\nfoo@bar:~$ ./main config -h\n\nUSAGE: config [FLAGS] [OPTIONS] name_value_pair\n\nFLAGS:\n    -g, --global\n\nOPTIONS:\n    -h, --help \u003chelp\u003e\n    -v, --version \u003cversion\u003e\n\nARGS:\n    name_value_pair\n\n\n\n\nfoo@bar:~$ ./main init -h\n\nUSAGE: init [OPTIONS] name\n\nOPTIONS:\n    -h, --help \u003chelp\u003e\n    -v, --version \u003cversion\u003e\n\nARGS:\n    name\n```\n\n***NOTE*** Notice in the above stdout that the `-h` help option supports printing help both at the top-level struct and at the sub-command level.\n\n***NOTE*** `structopt` does not allow to invoke multiple sub-commands. If one has already been invoked, you will see the following error:\n\n```console\nfoo@bar:~$ ./main config user.name \"John Doe\" init my_repo\nError: failed to invoke sub-command `init` because a different sub-command, `config`, has already been invoked.\n```\n\n### Sub-Commands, Vector Arguments, and Delimited Positional Arguments\n\nHere's a second example for nested structures with vector arguments and the double dash (`--`) delimiter\n\n```cpp\n#include \u003cstructopt/app.hpp\u003e\n\nstruct CommandOptions {\n  struct Sed : structopt::sub_command {\n    // --trace\n    std::optional\u003cbool\u003e trace = false;\n\n    // remaining args\n    std::vector\u003cstd::string\u003e args;\n\n    // pattern\n    std::string pattern;\n\n    // file\n    std::string file;\n  };\n  Sed sed;\n};\nSTRUCTOPT(CommandOptions::Sed, trace, args, pattern, file);\nSTRUCTOPT(CommandOptions, sed);\n\n\n\nint main(int argc, char *argv[]) {\n\n  auto app = structopt::app(\"my_app\");\n\n  try {\n\n    auto options = app.parse\u003cCommandOptions\u003e(argc, argv);\n\n    if (options.sed.has_value()) {\n      // sed has been invoked\n\n      if (options.sed.trace == true) {\n        std::cout \u003c\u003c \"Trace enabled!\\n\";\n      }\n\n      std::cout \u003c\u003c \"Args    : \";\n      for (auto\u0026 a : options.sed.args) std::cout \u003c\u003c a \u003c\u003c \" \"; \n      std::cout \u003c\u003c \"\\n\";\n      std::cout \u003c\u003c \"Pattern : \" \u003c\u003c options.sed.pattern \u003c\u003c \"\\n\";\n      std::cout \u003c\u003c \"File    : \" \u003c\u003c options.sed.file \u003c\u003c \"\\n\";\n    }\n    else {\n      std::cout \u003c\u003c app.help();\n    }\n\n  } catch (structopt::exception \u0026e) {\n    std::cout \u003c\u003c e.what() \u003c\u003c \"\\n\";\n    std::cout \u003c\u003c e.help();\n  }\n}\n```\n\n```console\nfoo@bar:~$ ./main\n\nUSAGE: my_app [OPTIONS] [SUBCOMMANDS]\n\nOPTIONS:\n    -h, --help \u003chelp\u003e\n    -v, --version \u003cversion\u003e\n\nSUBCOMMANDS:\n    sed\n\n\n\nfoo@bar:~$ ./main sed --trace X=1 Y=2 Z=3 -- 's/foo/bar/g' foo.txt\nTrace enabled!\nArgs    : X=1 Y=2 Z=3\nPattern : s/foo/bar/g\nFile    : foo.txt\n```\n\n### Printing Help\n\n`structopt` will insert two optional arguments for the user: `help` and `version`.\n\n* Using `-h` or `--help` will print the help message and exit.\n* Using `-v` or `--version` will print the program version and exit.\n\n```cpp\n#include \u003cstructopt/app.hpp\u003e\n\nstruct Options {\n  // positional arguments\n  std::string input_file;\n  std::string output_file;\n\n  // optional arguments\n  std::optional\u003cstd::string\u003e bind_address;\n\n  // remaining arguments\n  std::vector\u003cstd::string\u003e files;\n};\nSTRUCTOPT(Options, input_file, output_file, bind_address, files);\n\n\n\nint main(int argc, char *argv[]) {\n  auto options = structopt::app(\"my_app\", \"1.0.3\").parse\u003cOptions\u003e(argc, argv);\n}\n```\n\n```console\nfoo@bar:~$ ./main -h\n\nUSAGE: my_app [OPTIONS] input_file output_file files\n\nOPTIONS:\n    -b, --bind-address \u003cbind_address\u003e\n    -h, --help \u003chelp\u003e\n    -v, --version \u003cversion\u003e\n\nARGS:\n    input_file\n    output_file\n    files\n\nfoo@bar:~$ ./main -v\n1.0.3\n```\n\n### Printing CUSTOM Help\n\n`structopt` allows users to provide a custom help messages. Simply pass in your custom help as a string argument to `structopt::app`\n\n```cpp\n#include \u003cstructopt/app.hpp\u003e\n\nstruct Options {\n  // positional arguments\n  std::string input_file;\n  std::string output_file;\n\n  // optional arguments\n  std::optional\u003cstd::string\u003e bind_address;\n\n  // remaining arguments\n  std::vector\u003cstd::string\u003e files;\n};\nSTRUCTOPT(Options, input_file, output_file, bind_address, files);\n\nint main(int argc, char *argv[]) {\n\n  try {\n    const std::string\u0026 custom_help = \"Usage: ./my_app input_file output_file [--bind-address BIND_ADDRESS] [files...]\\n\";\n    auto options = structopt::app(\"my_app\", \"1.0.3\", custom_help).parse\u003cOptions\u003e(argc, argv);\n  } catch (structopt::exception \u0026e) {\n    std::cout \u003c\u003c e.what() \u003c\u003c \"\\n\";\n    std::cout \u003c\u003c e.help();\n  }\n}\n```\n\n```console\nfoo@bar:~$ ./main -h\nUsage: ./my_app input_file output_file [--bind-address BIND_ADDRESS] [files...]\n```\n\n## Building Samples and Tests\n\n```bash\ngit clone https://github.com/p-ranav/structopt\ncd structopt\nmkdir build \u0026\u0026 cd build\ncmake -DSTRUCTOPT_SAMPLES=ON -DSTRUCTOPT_TESTS=ON ..\nmake\n```\n\n### WinLibs + MinGW\n\nFor Windows, if you use [WinLibs](http://winlibs.com/) like I do, the cmake command would look like this:\n\n```console\nfoo@bar:~$ mkdir build \u0026\u0026 cd build\nfoo@bar:~$ cmake -G \"MinGW Makefiles\" -DCMAKE_CXX_COMPILER=\"C:/WinLibs/mingw64/bin/g++.exe\" -DSTRUCTOPT_SAMPLES=ON -DSTRUCTOPT_TESTS=ON ..\nfoo@bar:~$ make\n\nfoo@bar:~$ .\\tests\\structopt_tests.exe\n[doctest] doctest version is \"2.3.5\"\n[doctest] run with \"--help\" for options\n===============================================================================\n[doctest] test cases:     54 |     54 passed |      0 failed |      0 skipped\n[doctest] assertions:    393 |    393 passed |      0 failed |\n[doctest] Status: SUCCESS!\n```\n\n## Compiler Compatibility\n\n* Clang/LLVM \u003e= 5\n* MSVC++ \u003e= 14.11 / Visual Studio \u003e= 2017\n* Xcode \u003e= 10\n* GCC \u003e= 9\n\n## Generating Single Header\n\n```bash\npython3 utils/amalgamate/amalgamate.py -c single_include.json -s .\n```\n\n## Contributing\nContributions are welcome, have a look at the [CONTRIBUTING.md](CONTRIBUTING.md) document for more information.\n\n## License\nThe project is available under the [MIT](https://opensource.org/licenses/MIT) license.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fp-ranav%2Fstructopt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fp-ranav%2Fstructopt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fp-ranav%2Fstructopt/lists"}