2

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 :-)

andreee
  • 4,459
  • 22
  • 42
  • 1
    You can make it work by calling `c_str()` and it will not be dangerous. Arguments are `const char*` which means that the functions called with this args does not own the pointed memory, so it mus be copied for further processing after function returns. The same kind of copy would be invoked if the argument would be `const std::string&` – pptaszni Jan 16 '20 at 16:07

1 Answers1

2

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).

andreee
  • 4,459
  • 22
  • 42