Option Definitions

An Option describes one accepted command-line value. This page explains how option names, value types, repeated values, defaults, validation, flags, choices, and help metadata work together.

Start With the User-Facing Value

The most useful way to design an option is to start with the value the user wants to provide. Then decide how that value should be spelled on the command line and how application code should read it.

An option with at least one dashed name is a regular option. Long names such as --species are case-insensitive and are usually the most readable spelling. Short names such as -s are case-sensitive and are useful for common options. Dashless names on a regular option are lookup aliases only; they are not accepted on the command line.

An option without dashed names is a positional argument. Positionals are assigned in definition order and appear as placeholders in the generated usage line.

Use OptionEditor for Compact Definitions

Most code creates options through addOption(). The returned OptionEditor edits the new option and returns itself from each setter. This makes complete option declarations compact while still keeping the important details next to the name.

/// An `Option` definition describes names, type, defaults, list limits, choices, validation, and help text.
///
/// A dashed name such as `--instrument` is accepted on the command line.
/// A dashless name on the same regular option, such as `instrument`, is a lookup alias for `OptionValues`.
/// An option with only dashless names is a positional argument.
auto createDefinitionOptions() -> el::OptionsPtr {
    auto options = el::Options::create();
    auto info = el::ApplicationInfo{};
    info.setApplicationName("Optical Planner"_el);
    info.setApplicationVersion(el::Version{0, 8, 0});
    options->setApplicationInfo(info);
    options->setHelpTitle("Optical Planner"_el);
    options->setHelpDescription("Prepares a small measurement sequence for optical instruments."_el);
    options->addOption({"-i"_el, "--instrument"_el, "instrument"_el})
        .setType(el::OptionType::Text)
        .setRequired()
        .setHelpDescription("Instrument used for the sequence."_el);
    options->addOption({"-l"_el, "--level"_el, "level"_el})
        .setType(el::OptionType::Integer)
        .setMaximum(el::ArgumentCount{3U})
        .setHelpDescription("Intensity levels to test. Can be repeated up to three times."_el);
    options->addOption({"-m"_el, "--mode"_el, "mode"_el})
        .addChoice("fast"_el)
        .addChoice("precise"_el)
        .addChoice("night"_el)
        .setDefaultValue("precise"_el)
        .setHelpDescription("Measurement mode for the output."_el);
    options->addOption({"--minimum-signal"_el, "minimum-signal"_el})
        .setType(el::OptionType::Integer)
        .setDefaultValue(el::OptionInteger{3})
        .setValidateFn([](const el::OptionValuePtr &value, el::OptionValuesPtr) -> void {
            if (value->getInteger() < 1 || value->getInteger() > 9) {
                auto context = el::OptionErrorContext{};
                context.setDescription("The signal level must be between 1 and 9."_el);
                throw el::OptionError{context};
            }
        })
        .setHelpDescription("Minimum accepted signal on a scale from 1 to 9."_el);
    options->addOption("sample"_el).setHelpDescription("Sample placed in the optical holder."_el);
    return options;
}

auto definingOptions() -> el::ExitCode {
    auto manager = el::OptionManager{createDefinitionOptions()};
    auto args = makeArgs(
        {"optica"_el,
            "--instrument"_el,
            "Prisma-7"_el,
            "-l"_el,
            "1"_el,
            "--level=3"_el,
            "--mode=night"_el,
            "vidrio azul"_el});
    const auto values = manager.parseOrThrow(args);

    el::io::printLine("instrument: "_el, values->getText("instrument"_el));
    el::io::printLine("mode: "_el, values->getText("mode"_el));
    el::io::printLine("sample: "_el, values->getText("sample"_el));
    el::io::printLine("levels: "_el, values->getIntegerList("level"_el).size());
    el::io::printLine("minimum signal: "_el, values->getInteger("minimum-signal"_el));
    return el::ExitCode::success();
}
instrument: Prisma-7
mode: night
sample: vidrio azul
levels: 2
minimum signal: 3

Choose the Right Value Type

The parser supports six option types:

  • OptionType::Flag stores a valueless occurrence marker and remembers how often it appeared.

  • OptionType::Boolean parses a Boolean literal as a typed scalar or list value.

  • OptionType::Integer parses a signed decimal integer.

  • OptionType::Text stores one text value exactly as the command line supplied it after argument conversion.

  • OptionType::SensitiveText stores exactly one value in a marked String, masks its converted argument with five stars, and does not permit defaults, lists, or repeated occurrences.

  • OptionType::Choice accepts text from a configured choice list and stores the configured spelling.

Regular options default to Flag because a dashed option without a value is normally a switch. Positionals default to Text because a positional argument always consumes a value. Calling setType() makes the intent explicit. Calling addChoice() or setChoices() promotes the option to Choice.

Work With Choices

Choices are matched case-insensitively, but the parsed value uses the configured choice text. Use simple addChoice() calls when all choices only need a label. Use OptionChoices and OptionChoiceEditor when choices need their own help text or visibility.

Choice help is rendered as detail rows below the option. Hidden choices remain parseable, but do not appear in the help output.

/// Build a choice list when individual choices need their own help metadata.
///
/// `OptionEditor::addChoice()` is enough for simple choices.
/// `OptionChoices::addChoice()` returns an editor for adding help details to each choice.
/// Hidden choices remain accepted by the parser, but are omitted from generated help output.
[[nodiscard]] auto activityChoices() -> el::OptionChoicesPtr {
    auto choices = el::OptionChoices::create();

    choices->addChoice("dusk"_el).setHelpDescription("Activity around dusk."_el);
    choices->addChoice("night"_el).setHelpDescription("Activity in full darkness."_el);
    choices->addChoice("dawn"_el).setHelpDescription("Activity shortly before sunrise."_el);
    choices->addChoice("internal"_el)
        .setHelpDescription("Internal test choice that does not appear in regular help."_el)
        .setHelpVisibility(el::OptionHelpVisibility::Hidden);
    return choices;
}

/// Option definitions combine command-line names, value types, flags, choices, defaults, validation, and help text.
///
/// `OptionEditor` is returned from `addOption()`, so each option can be declared in one fluent expression.
/// Dashed names are accepted on the command line, while dashless names are lookup aliases for `OptionValues`.
/// Choices may carry their own help text, and visibility controls where an enabled option appears in generated help.
class NightWatchApp final : public el::Application {
public:
    using Application::Application;

protected:
    void initialize() override {
        enableTerminal();
        info().setApplicationName("Night Watch"_el);
        info().setApplicationVersion(el::Version{0, 8, 0});
    }
    void registerCommandLineOptions(const el::OptionsPtr &options) override {
        options->setHelpTitle("Night Watch"_el);
        options->setHelpDescription("Records short observations of nocturnal animal behavior."_el);
        options->setHelpEpilog("Hidden options remain usable, but do not appear in this help."_el);
        options->addOption({"-s"_el, "--species"_el, "species"_el})
            .setType(el::OptionType::Text)
            .setValueName("animal"_el)
            .setRequired()
            .setHelpDescription("Animal species tracked during the round."_el)
            .setHelpVisibility(el::OptionHelpVisibility::Usage);
        options->addOption({"-f"_el, "--phase"_el, "phase"_el})
            .setChoices(activityChoices())
            .setDefaultValue("night"_el)
            .setHelpDescription("Time window in which the observation occurs."_el);
        options->addOption({"-r"_el, "--round"_el, "round"_el})
            .setType(el::OptionType::Integer)
            .setDefaultValue(el::OptionInteger{2})
            .setValidateFn([](const el::OptionValuePtr &value, el::OptionValuesPtr) -> void {
                if (value->getInteger() < 1 || value->getInteger() > 6) {
                    auto context = el::OptionErrorContext{};
                    context.setTitle("Invalid round count"_el)
                        .setDescription("The round count must be between 1 and 6."_el);
                    throw el::OptionError{context};
                }
            })
            .setHelpDescription("Number of observation rounds in this area."_el);
        options->addOption({"-q"_el, "--quiet"_el, "quiet"_el})
            .setHelpDescription("Writes only the final result."_el)
            .setHelpVisibility(el::OptionHelpVisibility::Hidden);
        options->addOption({"--old-log"_el, "old-log"_el})
            .setFlag(el::OptionFlag::Disabled)
            .setHelpDescription("Old logging option that is no longer accepted."_el);
        options->addOption("area"_el)
            .setRequired()
            .setHelpDescription("Area where the observation takes place."_el);
    }
    [[nodiscard]] auto main() -> el::ExitCode override {
        const auto values = optionValues();
        el::io::printLine("species: "_el, values->getText("species"_el));
        el::io::printLine("area: "_el, values->getText("area"_el));
        el::io::printLine("phase: "_el, values->getText("phase"_el));
        el::io::printLine("rounds: "_el, values->getInteger("round"_el));
        el::io::printLine("quiet: "_el, el::BooleanFormat::yesNo(), values->getFlag("quiet"_el));
        return el::ExitCode::success();
    }
};

$ option/option_help_details --help

Records short observations of nocturnal animal behavior.

Usage:
  option_help_details [options] [--species <animal>] <area>

Options:
      <area>          Area where the observation takes place.
  -h, --help          Display this help.
  -f, --phase <choice>
                      Time window in which the observation occurs. Choices: dusk, night,
                      dawn.
      dusk   Activity around dusk.
      night  Activity in full darkness.
      dawn   Activity shortly before sunrise.
  -r, --round <integer>
                      Number of observation rounds in this area.
  -s, --species <animal>
                      Animal species tracked during the round.
      --version       Display version information.

Hidden options remain usable, but do not appear in this help.

$ option/option_help_details --species bat --phase dusk --quiet dune-edge

species: bat
area: dune-edge
phase: dusk
rounds: 2
quiet: yes

$ option/option_help_details --species bat --round 9 dune-edge

  Invalid round count

  The round count must be between 1 and 6.

Error Source:
  Command Line Arguments
  Argument: 4

Command Line Arguments:

     0 │ cmake-build-debug/demo-apps/option/option_help_details
     1 │ --species
     2 │ bat
     3 │ --round
     4 │ 9
     5 │ dune-edge

Usage:
  option_help_details [options] [--species <animal>] <area>

Option Help:
  -r, --round <integer>  Number of observation rounds in this area.

View Full Help:
  option_help_details --help

Repeated Values and Maximum

setMaximum() controls how many values an option may store. For a text or integer option, this turns the parsed result into a list. For a flag, repeated occurrences increase the flag count. Implicit repetitions such as -vv remain valid. An explicit boolean flag value is a complete assignment and therefore must occur exactly once; repeating it or mixing it with an implicit occurrence is a syntax error.

Repeated regular options may be supplied by repeating the option name. For positionals, the maximum controls how many positional values can be consumed for that definition. If a positional list should consume values greedily before later positionals are considered, add OptionFlag::Greedy. Use that deliberately, because greedy positionals make the grammar less self-evident.

Defaults and Validation

setDefaultValue() stores a static default in the option definition. When the user omits the option, the parser inserts that default into the result before application code reads OptionValues.

setValidateFn() installs a callback that runs after basic type parsing and default insertion, but before post-parsing callbacks are called. Throw OptionError with an OptionErrorContext when the value is syntactically valid but not valid for your domain.

Set a short title and a longer description when the distinction makes the error easier to scan. The parser supplies a reason-based title when a callback only provides a description. It also adds the current options, module, set, option, arguments and source index when they are known, so custom validation errors receive the same usage and contextual help as built-in parser errors.

Use validation for rules such as allowed ranges, relationships between options, or values that must match an external configuration. Keep basic type expectations in the option type itself.

Flags

OptionFlag changes parser behavior.

Disabled

Removes the option from parsing and generated help. A disabled option is different from a hidden option: hidden options still parse, disabled options do not.

Required

Requires the option or positional argument to be present after defaults are applied. OptionEditor::setRequired() is the common shorthand.

Greedy

Allows a positional list option to consume values greedily. It is meaningful for positional list definitions; it is not a general replacement for explicit command syntax.

AcceptAsFlag

Allows a named, non-positional scalar value option to appear without a value. Bare use is available through getFlag(), while valued use is available through the declared typed getter. The definition must accept exactly one value. It has no additional effect on Flag and no behavior on option sets.

Customize Option Help

Every option stores OptionHelp. For ordinary definitions, use the direct editor methods: setHelpDescription(), setHelpTitle(), setHelpExample(), setHelpEpilog(), and setHelpVisibility().

The description is the main text shown next to the option. The title is used by renderers when a short label is needed. The example is shown in detailed --help=<name> output. The epilog is available for renderers that expose trailing option details. The value name changes the placeholder shown in help, for example <dier> instead of the generic <value>.

Help Visibility

OptionHelpVisibility controls where enabled options appear. It never disables parsing.

Inherit

Uses the owning option set visibility, or Normal when no owner provides one.

Hidden

Keeps the option parseable while hiding it from generated help. Use this for compatibility switches, debug toggles, or integration options that should not distract regular users.

Normal

Shows the option in help for the active root or module.

Overview

Also shows the option in root overview help when modules exist. Use this for global options that users may need before choosing a module.

Usage

Behaves like Overview and renders regular options explicitly in the usage line. Use it sparingly for options that are central to understanding the command.