Consider this MCVE:
#include <boost/program_options.hpp>
#include <iostream>
#include <map>
namespace po = boost::program_options;
using namespace std;
po::options_description createOptions(const std::string& description, const map<string, string>& opts) {
po::options_description newoptions(description);
for (const auto& [k, v] : opts) {
newoptions.add_options()(k, v);
}
return newoptions;
}
int main() {
map<string, string> descMap = {
{ "key", "description" },
{ "hello", "world" }
};
auto opts = createOptions("My options", descMap);
cout << opts << endl;
}
I am trying to write a convenience function to reduce the amount of C&P code when inserting similar options into an options_description
object (the original code uses notifiers which were removed for simplicity, but add even more boilerplate).
To my surprise, there is no options_description_easy_init::operator()
overload that accepts std::string
, thus the example fails to compile.
While I could easily make the example work by calling .c_str()
on k
and v
within the for loop, of course this would be dangerous. Is there any reason why the boost devs left out such an important overload? Why didn't they use const std::string&
as argument in the first place?
And how can I make this code work without .c_str()
? There is no indication that the pointer memory will be copied internally (which would be odd anyway) and I really don't feel like going back in time and managing memory on my own :-)
Looking into the implementation, it seems that internally the const char*
argument passed to options_description_easy_init::operator()
is wrapped by a new option_description
object, which eventually converts the argument into a std::string
. So as commented by @pptaszni, it is safe to call .c_str()
on the std::string
arguments to pass them to the program options.
What I still don't understand, however, is why there is not an std::string
overload. I consider this a design flaw (also considering that options_description
has a constructor taking std::string
).