po::options_description desc("This are the options that are available");
desc.add_options()("help", "print help")(
"deer", po::value<uint32_t>(), "set how many deer you want")(
"rating", po::value<uint32_t>(), "how good ?")(
"name", po::value<std::string>(), "and your name is ... ?");
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
po::notify(vm);
in a following section of the code I tried to iterate over vm
for (const auto& it : vm) {
std::cout << it.first.c_str() << " "
<< it.second.as<it.pair::second_type>() << "\n";
}
The main point here is that vm
contains keys
of the same type, but values with different types, in this example I have uint32_t
mixed with a std::string
.
How I can iterate over this kind of containers ? I would like to avoid a verbose approach so I'm trying to just iterate over this data structure.
EDIT:
I forgot to write this down, but obviously
namespace po = boost::program_options;
boost variable_map
use boost::any
as the value so you can try to use boost::any_cast<T>
to find out the type.
perhaps something like this
for (const auto& it : vm) {
std::cout << it.first.c_str() << " ";
auto& value = it.second.value();
if (auto v = boost::any_cast<uint32_t>(&value))
std::cout << *v;
else if (auto v = boost::any_cast<std::string>(&value))
std::cout << *v;
else
std::cout << "error";
}
boost::program_options::variable_map
is essentially an std::map<std::string, boost::any>
, which means it uses type erasure to store the values. Because the original type is lost, there's no way to extract it without casting it to the correct type. You could implement a second map
that contains the option name as key, and the extraction function as value, allowing you to dispatch the value to the appropriate extractor at runtime.
using extractor = std::map<std::string, void(*)(boost::variable_value const&)>;
or
using extractor = std::map<std::string,
std::function<void(boost::variable_value const&)>;
if your extractors are more complicated and will not convert to a simple function pointer. An example of an extractor that'll print a uint32_t
is
auto extract_uint32_t = [](boost::variable_value const& v) {
std::cout << v.as<std::uint32_t>();
};
Then your loop would look like this:
for (const auto& it : vm) {
std::cout << it.first.c_str() << " "
extractor_obj[it.first](it.second)
std::cout << "\n";
}
Here's a live demo with some made up types, but it's close enough to your use case that you should be able to apply something similar.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With