Skip to content

Examples

idimus edited this page Jul 10, 2026 · 15 revisions

Full text of example from tutorial

#include <iostream>
#include "ArgParse/argparse.h"

int main(int argc, char** argv)
{
    auto parser = argparse::ArgumentParser("Program name").SetDescription("Description of program");
    parser.AddArgument(argparse::CreateNamedArgument()
        .SetLongName("numbers")
        .SetAnyNumberOfArgumentsButAtleastOne()
        .SetType(argparse::ArgTypeCast::e_int));
    parser.AddArgument(argparse::CreateNamedArgument()
        .SetLongName("some_boring_long_name")
        .SetAnyNumberOfArgumentsButAtleastOne()
        .SetType(argparse::ArgTypeCast::e_int)
        .SetHelp("some_boring_long_name description with some important information for user.")
        .SetRequired(false));

    auto obj = parser.ParseArgs(argc, argv);
    if (obj.IsArgValid())
    {
        auto arg = obj.GetArg("numbers");
        if (arg.GetArgumentExists())
        {
            for (auto& el : arg.GetAsVecInt())
            {
                std::cout << el << std::endl;
            }
        }
    }
    else
    {
        std::string help = parser.GetHelp(80);
        std::cout << obj.GetErrorString() << std::endl;
        std::cout << help << std::endl;
    }

    return 0;
}

This exmaple will create program with keys -n, --number, -s, --some_boring_long_name, -h and --help. Help will be autogenerated. The types of numbers and some_boring_long_name are integers with count from 1 to infinite.

Typical output without any arguments:

main.cpp [-n,--numbers [n ...] ] [-s,--some_boring_long_name [s ...] ] -h,--help
Description of program

optional arguments:

-n,--numbers            some numbers description with some important information
                        for user. Type: INT. Args count: at least one.
-s,--some_boring_long_name
                        some_boring_long_name description with some important information
                        for user. Type: INT. Args count: at least one.
-h,--help               Show help!

Note actually terminal cannot get infinite numbers of arguments. In most cases maximum length of all input that terminal can pass is limited with 8 kb.

Full text of example from tutorial but shorter way

#include <iostream>
#include "ArgParse/argparse.h"

int main(int argc, char** argv)
{
    auto parser = argparse::ArgumentParser(__FILE__).SetDescription("Description of program");

    parser.AddArgument(argparse::CreateNamedArgument("n", "numbers", argparse::kFromOneToInfinteArgCount,
        argparse::ArgTypeCast::e_int, false, 
        "some numbers description with some important information for user."));
    parser.AddArgument(argparse::CreateNamedArgument("s", "some_boring_long_name", argparse::kFromOneToInfinteArgCount,
        argparse::ArgTypeCast::e_int, false, 
        "some_boring_long_name description with some important information for user."));
    auto obj = parser.ParseArgs(argc, argv);
    if (obj.IsArgValid())
    {
        auto arg = obj.GetArg("numbers");
        if (arg.GetArgumentExists())
        {
            for (auto& el : arg.GetAsVecInt())
            {
                std::cout << el << std::endl;
            }
        }
    }
    else
    {
        std::string help = parser.GetHelp(80);
        std::cout << obj.GetErrorString() << std::endl;
        std::cout << help << std::endl;
    }

    return 0;
}

Making 1 required argument, with 1 required value

generic -h, --help is suppressed example compiles for c++17 and uses std::any approach

#include <iostream>
#include "ArgParse/argparse.h"

int main(int argc, char** argv)
{
    auto parser = argparse::ArgumentParser("main").SetDescription("ArgParse example");

    parser.AddArgument(argparse::CreateNamedArgument("b", "b_key", 1,  argparse::ArgTypeCast::e_int, true, 
        R"=(some "b_key" description with some important information for user)="));

    parser.SetAddHelp(false);

    auto obj = parser.ParseArgs(argc, argv);
    if (obj.IsArgValid())
    {
        auto arg = obj.GetArg("b_key");
        std::cout << arg.Get().type().name() << ": " << std::any_cast<int>(arg.Get()) << std::endl;
    }
    else
    {
        std::string help = parser.GetHelp(80);
        std::cout << obj.GetErrorString() << std::endl;
        std::cout << help << std::endl;
    }

    return 0;
}

You can change 1 to 0 from this example. It will be flag, and you cannot access to it's content.

Adding positional argument

Positional argument should be inputted as raw argument without any key. This is only difference between keyed and positional arguments.

#include <iostream>
#include "ArgParse/argparse.h"

int main(int argc, char** argv)
{
    auto parser = argparse::ArgumentParser("main").SetDescription("ArgParse example");

    parser.AddArgument(argparse::CreatePositionalArgument("int1")
          .SetType(argparse::ArgTypeCast::e_int).SetRequired(false));

    auto obj = parser.ParseArgs(argc, argv);
    if (obj.IsArgValid())
    {
        auto arg = obj.GetArg("int1");
        if (arg.GetArgumentExists())
        {
            std::cout << arg.Get().type().name() << ": " << std::any_cast<int>(arg.Get()) << std::endl;
        }
    }
    else
    {
        std::string help = parser.GetHelp(80);
        std::cout << obj.GetErrorString() << std::endl;
        std::cout << help << std::endl;
    }

    return 0;
}

Simple polish notation calc

#include <iostream>
#include "ArgParse/argparse.h"

int main(int argc, char** argv)
{
    auto parser = argparse::ArgumentParser("main").SetDescription("ArgParse example");

    parser.AddArgument(argparse::CreatePositionalArgument("nums").SetType(argparse::ArgTypeCast::e_double).SetNumberOfArguments(2));
    parser.AddArgument(argparse::CreateNamedArgument("o", "operation").SetRequired(true).SetChoices({"+","-","*","/"}));
    parser.SetEpilogue("This is example of epilogue. Will be placed in the end of help");

    auto obj = parser.ParseArgs(argc, argv);
    if (obj.IsArgValid())
    {
        auto arg = obj.GetArg("nums");
        auto op = obj.GetArg("operation");

        const std::vector<double>& nums = arg.GetAsVecDouble();
        const std::string& operation = op.GetAsString();
        std::cout << nums[0] << operation << nums[1] << "=";
        if (operation == "+")
        {
            std::cout << nums[0] + nums[1] << std::endl;
        }
        else if (operation == "-")
        {
            std::cout << nums[0] - nums[1] << std::endl;

        }
        else if (operation == "*")
        {
            std::cout << nums[0] * nums[1] << std::endl;
        }
        else //if(operation == "/")
        {
            std::cout << nums[0] / nums[1] << std::endl;

        }
    }
    else
    {
        std::string help = parser.GetHelp(80);
        std::cout << obj.GetErrorString() << std::endl;
        std::cout << help << std::endl;
    }

    return 0;
}
usage examples
>>> calc.exe 12121 222 -o +
12121+222=12343

>>> calc.exe 12121 222 -o %
Value '%' is out of choices for "operation"
main nums [nums nums] -o,--operation [{+, -, *, /}] [-h,--help]
ArgParse example

positional arguments:

nums                    Type: DOUBLE. Args count: 2


named arguments:

-o,--operation          Type: STRING. Choices:+, -, *, /. Args count: 1
-h,--help               Show help!

This is example of epilogue. Will be placed in the end of help

Flags and default values

A flag holds no value — it is either present or not — created with SetArgumentIsFlag(). Remember that every argument is required by default, so an optional flag must opt out with SetRequired(false). SetDefault(...) gives an optional argument a value to fall back on when the user omits it.

#include <iostream>
#include "ArgParse/argparse.h"

int main(int argc, char** argv)
{
    auto parser = argparse::ArgumentParser("build").SetDescription("Flags and default values");

    parser.AddArgument(argparse::CreateNamedArgument("v", "verbose").SetArgumentIsFlag()
        .SetRequired(false)
        .SetHelp("Enable verbose output"));

    parser.AddArgument(argparse::CreateNamedArgument("j", "jobs", 1, argparse::ArgTypeCast::e_int, false)
        .SetDefault(1)
        .SetHelp("Number of parallel jobs (default: 1)"));

    auto obj = parser.ParseArgs(argc, argv);
    if (!obj.IsArgValid())
    {
        std::cout << obj.GetErrorString() << "\n" << parser.GetHelp(80) << std::endl;
        return 1;
    }

    const bool verbose = obj.GetArg("verbose").GetArgumentExists();
    const int jobs = obj.GetArg("jobs").GetAsInt(); // always present thanks to SetDefault

    std::cout << "verbose = " << (verbose ? "true" : "false") << "\n";
    std::cout << "jobs    = " << jobs << std::endl;
    return 0;
}
>>> build -v
verbose = true
jobs    = 1

>>> build
verbose = false
jobs    = 1

Mixing positional and named arguments

Positional and named arguments can be combined freely. Below, a small cp-like tool takes two positionals (source, dest) and one named flag (-f/--force).

Important: getters that return a reference — GetAsString() and the GetAsVec*() family — return a reference into the ArgumentParsed object. Store the result of GetArg(...) in a variable before calling them, otherwise the reference dangles. (Value getters like GetAsInt()/GetAsDouble() return by value and are always safe.)

#include <iostream>
#include "ArgParse/argparse.h"

int main(int argc, char** argv)
{
    auto parser = argparse::ArgumentParser("mycp").SetDescription("Copy SOURCE to DEST");

    parser.AddArgument(argparse::CreatePositionalArgument("source").SetHelp("File to copy from"));
    parser.AddArgument(argparse::CreatePositionalArgument("dest").SetHelp("File to copy to"));

    parser.AddArgument(argparse::CreateNamedArgument("f", "force").SetArgumentIsFlag()
        .SetRequired(false)
        .SetHelp("Overwrite destination if it exists"));

    auto obj = parser.ParseArgs(argc, argv);
    if (!obj.IsArgValid())
    {
        std::cout << obj.GetErrorString() << "\n" << parser.GetHelp(80) << std::endl;
        return 1;
    }

    // Store the ArgumentParsed before reading string references from it.
    auto sourceArg = obj.GetArg("source");
    auto destArg = obj.GetArg("dest");
    const std::string& src = sourceArg.GetAsString();
    const std::string& dst = destArg.GetAsString();
    const bool force = obj.GetArg("force").GetArgumentExists();

    std::cout << "copy " << src << " -> " << dst << (force ? " (force)" : "") << std::endl;
    return 0;
}
>>> mycp a.txt b.txt -f
copy a.txt -> b.txt (force)

Error handling patterns

There are two distinct kinds of errors:

  • Setup errors — a malformed definition, e.g. an argument with neither a name nor a positional name. AddArgument throws for these; they are programmer mistakes. You only need a try/catch if you build arguments dynamically from external data.
  • Input errors — bad user input (missing required argument, wrong type, value out of choices). These are never thrown; they are reported through the result object via IsArgValid() and GetErrorString().
#include <iostream>
#include "ArgParse/argparse.h"

int main(int argc, char** argv)
{
    argparse::ArgumentParser parser("app");

    try
    {
        parser.AddArgument(argparse::CreateNamedArgument("p", "port", 1, argparse::ArgTypeCast::e_int, true)
            .SetHelp("Port to listen on"));
    }
    catch (const std::exception& e)
    {
        std::cerr << "argument setup error: " << e.what() << std::endl;
        return 2;
    }

    auto obj = parser.ParseArgs(argc, argv);
    if (!obj.IsArgValid())
    {
        std::cerr << "error: " << obj.GetErrorString() << "\n\n";
        std::cerr << parser.GetHelp(80) << std::endl;
        return 1;
    }

    std::cout << "listening on port " << obj.GetArg("port").GetAsInt() << std::endl;
    return 0;
}
>>> app -p 8080
listening on port 8080

>>> app
error: Required argument with name "port" doesn't exists

app -p,--port [p] [-h,--help]

named arguments:

-p,--port                Port to listen on Type: INT. Args count: 1
-h,--help                Show help!

Real-world example: temperature converter

Combines a typed positional (double), two required named arguments constrained with SetChoices, and an epilogue.

#include <iostream>
#include "ArgParse/argparse.h"

int main(int argc, char** argv)
{
    auto parser = argparse::ArgumentParser("convert").SetDescription("Convert a temperature between units");

    parser.AddArgument(argparse::CreatePositionalArgument("value")
        .SetType(argparse::ArgTypeCast::e_double).SetHelp("Temperature value"));
    parser.AddArgument(argparse::CreateNamedArgument("f", "from").SetRequired(true)
        .SetChoices({"C", "F", "K"}).SetHelp("Source unit"));
    parser.AddArgument(argparse::CreateNamedArgument("t", "to").SetRequired(true)
        .SetChoices({"C", "F", "K"}).SetHelp("Target unit"));
    parser.SetEpilogue("Units: C = Celsius, F = Fahrenheit, K = Kelvin");

    auto obj = parser.ParseArgs(argc, argv);
    if (!obj.IsArgValid())
    {
        std::cout << obj.GetErrorString() << "\n" << parser.GetHelp(80) << std::endl;
        return 1;
    }

    auto fromArg = obj.GetArg("from");
    auto toArg = obj.GetArg("to");
    const double v = obj.GetArg("value").GetAsDouble(); // returns by value: safe inline
    const std::string& from = fromArg.GetAsString();
    const std::string& to = toArg.GetAsString();

    double c = from == "C" ? v : from == "F" ? (v - 32.0) * 5.0 / 9.0 : v - 273.15;
    double out = to == "C" ? c : to == "F" ? c * 9.0 / 5.0 + 32.0 : c + 273.15;

    std::cout << v << from << " = " << out << to << std::endl;
    return 0;
}
>>> convert 100 -f C -t F
100C = 212F

>>> convert 100 -f C -t Q
Value 'Q' is out of choices for "to"

Variable argument count, custom prefix and ignore-unknown

kAnyArgCount accepts zero or more values (use kFromOneToInfinteArgCount to demand at least one). SetPrefixChars('+') changes the option prefix, and SetIgnoreUknownArgs(true) lets the parser skip options it doesn't recognise instead of failing.

#include <iostream>
#include "ArgParse/argparse.h"

int main(int argc, char** argv)
{
    auto parser = argparse::ArgumentParser("sum")
        .SetDescription("Sum any amount of numbers")
        .SetPrefixChars('+')
        .SetIgnoreUknownArgs(true);

    parser.AddArgument(argparse::CreateNamedArgument("n", "nums", argparse::kAnyArgCount,
        argparse::ArgTypeCast::e_int, false).SetHelp("Numbers to add"));

    auto obj = parser.ParseArgs(argc, argv);
    if (!obj.IsArgValid())
    {
        std::cout << obj.GetErrorString() << "\n" << parser.GetHelp(80) << std::endl;
        return 1;
    }

    long long total = 0;
    auto arg = obj.GetArg("nums");
    if (arg.GetArgumentExists())
        for (int n : arg.GetAsVecInt())
            total += n;

    std::cout << "sum = " << total << std::endl;
    return 0;
}
>>> sum ++nums 3 4 5 ++junk hello
sum = 12

Using a custom namespace

If the default argparse namespace clashes with something in your project, define ARGPARSE_NAMESPACE_NAME before including the header to rename it.

#define ARGPARSE_NAMESPACE_NAME cli
#include <iostream>
#include "ArgParse/argparse.h"

int main(int argc, char** argv)
{
    auto parser = cli::ArgumentParser("greet").SetDescription("Custom namespace demo");
    parser.AddArgument(cli::CreateNamedArgument("n", "name", 1, cli::ArgTypeCast::e_String, true)
        .SetHelp("Who to greet"));

    auto obj = parser.ParseArgs(argc, argv);
    if (!obj.IsArgValid())
    {
        std::cout << obj.GetErrorString() << "\n" << parser.GetHelp(80) << std::endl;
        return 1;
    }
    std::cout << "Hello, " << obj.GetArg("name").GetAsString() << "!" << std::endl;
    return 0;
}
>>> greet --name World
Hello, World!

Clone this wiki locally