Print help for both normal and positional args with boost::program_options
Asked Answered
L

3

21

When you use Boost library program_options it is very easy to print help for your program:

boost::program_options::variables_map options;
boost::program_options::options_description optionsDesc;
boost::program_options::positional_options_description positionalOptionsDesc;
//...
if(options.count("help"))
{
    cerr << optionsDesc << endl;
}

But how do you add the options from positional_options_description to the help message? In the tutorial I can see the output of such set-up, at the end of the section:

http://www.boost.org/doc/libs/1_52_0/doc/html/program_options/tutorial.html#id2607297

The option input-file is printed in help and it is positional. But I can't see the code. Is there an build-in way to print it, like with options_description or you have to do it manually? Apparently the << does not work for positional_options_description, the compilation error is:

error: cannot bind ‘std::ostream {aka std::basic_ostream<char>}’ lvalue to ‘std::basic_ostream<char>&&’
Lemons answered 2/1, 2013 at 17:30 Comment(2)
If it helps, you can find the full code here.Beneficiary
Thanks llonesmiz, it indeed helped a lot! I though that I don't have to add positional args to options_description if I add them to positional_options_description, but you have to add to both.Lemons
E
6

Notice that streaming description only prints out the options. It does not print the name of the program or the actual description of what the program does. You should manually print any positional parameter you have as part of the output message:

Instead of

if (vm.count("help")) {
    cout << "Usage: options_description [options]\n";
    cout << desc;
    return 0;
}

You could easily say

if (vm.count("help")) {
    cout << "Usage: " << argv[0] << " [options] <description of positional 1> <description of positional 2> ...\n";
    cout << desc;
    return 0;
}
Exclusion answered 2/1, 2013 at 19:3 Comment(1)
As I said in the comment to the question I wasn't adding my positional arg to options_description, only to positional_options_description. That's why it didn't got printed. It normally does, so you're code does what I wanted, I just made mistake in the other place. I also agree it is nice to print the usage in the beginning.Lemons
M
2

Have a look at boost::program_options::positional_options_description.name_for_position(i)

The error message is something unrelated, I forget what eactly something to do with cpp11

Mapping answered 2/1, 2013 at 19:6 Comment(0)
C
2

This is what I do for automatically printing positional options:

void printUsage(const std::string &argv0)
{
    std::ostream &os = std::cout;

    os << "Usage:" << std::endl;

    // print only basename of argv[0]
    boost::filesystem::path p(argv0);
    os << "  " << p.filename().string();

    os << " [options]";

    std::string last = "";
    int rep = 0;
    for(int i = 0; i < positional_options_description_.max_total_count(); i++)
    {
        const std::string &n = positional_options_description_.name_for_position(i);
        if(n == last)
        {
            if(!rep) os << " ...";
            if(rep++ > 1000) break;
        }
        else
        {
            os << " " << n;
            last = n;
            rep = 0;
        }
    }
    os << std::endl << std::endl;
    os << options_description_ << std::endl;
}

The logic for checking repeated argument names is needed only if you have repeated options that can repeat an infinite number of times, i.e. with count equal to -1, otherwise you can simplify this a little bit, e.g. replace the if... else if ... with os << " " << n;.

With current (1.68) version of boost, there is no way of telling if an option description is positional or not, so there is nothing to do to improve the help, for example, excluding positional options from being printed.

Cordovan answered 28/11, 2018 at 8:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.