Regarding the question asked in the heading, “How to add a description for boost :: program_options” positional parameters? ", there is no functionality for this in the library. You must handle this part yourself.
As for the body of the question ... it is possible, but a little around.
Positional parameters map each position to a name, and names must exist. From what I can say in the code ( cmdline.cpp ), the unregistered flag unregistered not be set for arguments that are positional. [ 1 ], [ 2 ]
So, to do what you want, we can do the following:
- Hide the
--files from showing in the help. You will need to display the appropriate help for the positional parameters yourself, but this is no different from the previous one. - Add our own check between parsing and storing parsed options in
variables_map .
Hiding --files with
Here we take advantage of the fact that we can create composite options_description using the add(...) member function:
po::options_description desc_1; // ... po::options_description desc_2; // ... po::options_description desc_composite; desc_composite.add(desc_1).add(desc_2);
Therefore, we can put our files parameter in a hidden options_description and create a composite, which we will use only for the parsing stage. (see code below)
Preventing Explicit --files
We need to intercept a list of parameters between parsing and storing them in variables_map .
The run() method command_line_parser returns an instance of basic_parsed_options whose member options contains the vector basic_option s. There is an element for each argument analyzed, and any positional parameters are listed starting at 0 , any non-positional options have a position of -1 . We can use this to perform our own validation and raise errors when we see --files as an explicit (non-positional) argument.
Source code example
See on Coliru
#include <boost/program_options.hpp> #include <iostream> #include <string> #include <vector> namespace po = boost::program_options; int main(int argc, const char* argv[]) { std::vector<std::string> file_names; po::options_description desc("Allowed options"); desc.add_options() ("help", "produce help message") ("test", "test option"); std::string const FILES_KEY("files"); // Hide the `files` options in a separate description po::options_description desc_hidden("Hidden options"); desc_hidden.add_options() (FILES_KEY.c_str(), po::value(&file_names)->required(), "list of files"); // This description is used for parsing and validation po::options_description cmdline_options; cmdline_options.add(desc).add(desc_hidden); // And this one to display help po::options_description visible_options; visible_options.add(desc); po::positional_options_description pos; pos.add(FILES_KEY.c_str(), -1); po::variables_map vm; try { // Only parse the options, so we can catch the explicit `--files` auto parsed = po::command_line_parser(argc, argv) .options(cmdline_options) .positional(pos) .run(); // Make sure there were no non-positional `files` options for (auto const& opt : parsed.options) { if ((opt.position_key == -1) && (opt.string_key == FILES_KEY)) { throw po::unknown_option(FILES_KEY); } } po::store(parsed, vm); po::notify(vm); } catch(const po::error& e) { std::cerr << "Couldn't parse command line arguments properly:\n"; std::cerr << e.what() << '\n' << '\n'; std::cerr << visible_options << '\n'; return 1; } if (vm.count("help") || !vm.count("files")) { std::cout << desc << "\n"; return 1; } if (!file_names.empty()) { std::cout << "Files: \n"; for (auto const& file_name : file_names) { std::cout << " * " << file_name << "\n"; } } }
Test output
Valid parameters:
>example abc --test de Files: * a * b * c * d * e
Invalid parameters:
>example abc --files de Couldn't parse command line arguments properly: unrecognised option 'files' Allowed options: --help produce help message --test test option