Skip to main content

Callback Entry Point

Open this when parsing should populate application state for some other entry point, service object, or orchestration function.

This page is the bridge between cli20 and a larger application architecture. The parser gathers state first, and then your real program entry point runs with that prepared state.

Source​

Source: examples/callback_entry_point.cc

examples/callback_entry_point.cc
// callback_entry_point.cc — demonstrates using on_parse callbacks to populate
// an application state object before handing off to the real entry point.

#include <iostream>

#include "cli/argument.hh"
#include "cli/parser.hh"

struct AppState {
bool verbose = false;
int jobs = 1;
std::vector<std::string> includes;
std::vector<std::string> inputs;
};

struct Args {
cli::Description description{
"Populate application state via callbacks, then call the real entry "
"point."};
cli::Help<> help;
cli::Flag<"verbose", 'v'> verbose;
cli::IntOption<"jobs", 'j'> jobs;
cli::ListOption<std::string, "include", 'I', cli::nargs::exactly<1>> includes;
cli::Positional<std::string, cli::nargs::one_or_more> inputs;
};

auto run(const AppState& state) -> int {
std::cout << "verbose: " << std::boolalpha << state.verbose << '\n';
std::cout << "jobs: " << state.jobs << '\n';
for (const auto& include_dir : state.includes) {
std::cout << "include: " << include_dir << '\n';
}
for (const auto& input : state.inputs) {
std::cout << "input: " << input << '\n';
}
return 0;
}

auto main(int argc, char* argv[]) -> int {
AppState state;
Args args;

args.verbose = cli::Flag<"verbose", 'v'>{{
.on_parse = [&state](const bool& value) -> void { state.verbose = value; },
}};
args.jobs = cli::IntOption<"jobs", 'j'>{{
.on_parse = [&state](const int& value) -> void { state.jobs = value; },
}};
args.includes =
cli::ListOption<std::string, "include", 'I', cli::nargs::exactly<1>>{{
.on_parse = [&state](const std::vector<std::string>& value) -> void {
state.includes = value;
},
}};
args.inputs = cli::Positional<std::string, cli::nargs::one_or_more>{{
.on_parse = [&state](const std::vector<std::string>& value) -> void {
state.inputs = value;
},
}};

const auto result = cli::Parser<Args>{}.parse(std::move(args), argc, argv);
if (!result) {
std::cerr << result.error.message() << '\n';
return result.error.exit_code();
}

return run(state);
}

What This Example Shows​

This example updates application state incrementally as each argument is parsed and then hands the finished state to the real entry point. It keeps CLI wiring at the edge, supports repeated --include options without swallowing positionals, and leaves the final state in verbose, jobs, includes, and inputs.

Try It​

cli20@cli20-dev: ~
cli20@cli20-dev:~$ callback_entry_point

Things to try:

  • Happy path — --verbose --jobs 8 --include src --include include main.cc lib.cc
  • Help — --help
  • Multiple includes — add more --include path flags to see the list grow
  • No inputs — --verbose to see what happens with no positional arguments