Search code examples
c++boostboost-program-options

Boost::program_options how to parse multiple multi_tokens


is it possible to parse multiple mulit-token parameters with the same name?

Like: program.exe --param a b c --param foo bar ?

I only could get it to work like this: program.exe --param "a b c" --param "foo bar" but then I have to split the parameter myself.

[...]
options.add_options()("param", po::value<vector<string>>()->multitoken()               
    , "description")
[...]

thanks for any hints


Solution

  • I think you want a combination of composing and multi-token:

    Live On Coliru

    #include <boost/program_options.hpp>
    #include <fmt/ranges.h>
    namespace po = boost::program_options;
    using strings = std::vector<std::string>;
    
    int main(int argc, char** argv) {
        po::options_description opts;
        opts.add_options()("param",
                           po::value<strings>()
                               ->multitoken()
                               ->composing()
                               ->default_value({}, "")
                               ->implicit_value({}, ""),
                           "you know the drill");
    
        po::variables_map vm;
        store(parse_command_line(argc, argv, opts), vm);
    
        if (vm.contains("param")) {
            fmt::print("Params: {}\n", vm["param"].as<strings>());
        }
    }
    

    Which prints e.g.:

    + ./a.out
    Params: []
    + ./a.out --param
    Params: []
    + ./a.out --param a b
    Params: ["a", "b"]
    + ./a.out --param a b --param c d
    Params: ["a", "b", "c", "d"]
    

    Note, if you don't want to allow --param without a value, remove the implicit_value: Live On Coliru

    UPDATE

    To the comment:

    You can always use the parser section of the library, inspecting the parsed_options instance:

    // using parsed-options to see "source" material:
    auto parsed = parse_command_line(argc, argv, opts);
    for (auto& po : parsed.options) {
        auto key = po.position_key == -1 //
            ? po.string_key
            : '#' + std::to_string(po.position_key);
    
        fmt::print("Option {}: {}\n", key, po.value);
    }
    
    // original logic:
    store(parsed, vm);
    
    if (vm.contains("param")) {
        fmt::print("Effective combined params: {}\n", vm["param"].as<strings>());
    }
    

    See it Live On Coliru, printing:

    + ./a.out
    Effective combined params: []
    + ./a.out --param
    Option param: []
    Effective combined params: []
    + ./a.out --param a b
    Option param: ["a", "b"]
    Effective combined params: ["a", "b"]
    + ./a.out --param a b --param c d
    Option param: ["a", "b"]
    Option param: ["c", "d"]
    Effective combined params: ["a", "b", "c", "d"]