Boost program options iterate over variables_map

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.