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 tooptions_description_easy_init::operator()is wrapped by a newoption_descriptionobject, which eventually converts the argument into astd::string. So as commented by @pptaszni, it is safe to call.c_str()on thestd::stringarguments to pass them to the program options.What I still don't understand, however, is why there is not an
std::stringoverload. I consider this a design flaw (also considering thatoptions_descriptionhas a constructor takingstd::string).