2014-01-08 2 views
5
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 einem folgenden Abschnitt des Codes Ich habe versucht, hier iterieren vmBoost-Programmoptionen iterieren variables_map

for (const auto& it : vm) { 
     std::cout << it.first.c_str() << " " 
       << it.second.as<it.pair::second_type>() << "\n"; 
    } 

Der wichtigste Punkt ist, dass vm enthält keys des gleichen Typs, aber Werte mit unterschiedlichen Typen, in diesem Beispiel habe ich uint32_t gemischt mit einem std::string.

Wie kann ich über diese Art von Containern iterieren? Ich möchte einen ausführlichen Ansatz vermeiden, deshalb versuche ich, einfach über diese Datenstruktur zu iterieren.

EDIT:

Ich habe vergessen, dies aufzuschreiben, aber offensichtlich

namespace po = boost::program_options; 

Antwort

10

boost variable_map Verwenden Sie boost::any als Wert, so können Sie versuchen, boost::any_cast<T> zu verwenden, um den Typ herauszufinden. vielleicht etwas wie das

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"; 
} 
0

Ich habe nicht in die boost :: program_options Vorlage speziell gesucht, aber Sie könnten wahrscheinlich tun etwas generisch wie Verwendung Vorlagenfunktionen, die den Befehl je nach Typ unterschiedlich analysieren:

2

boost::program_options::variable_map ist im Wesentlichen ein , was bedeutet, dass es Typlöschung verwendet, um die Werte zu speichern. Da der Originaltyp verloren geht, können Sie ihn nicht extrahieren, ohne ihn in den richtigen Typ zu konvertieren. Sie könnten eine zweite map implementieren, die den Optionsnamen als Schlüssel und die Extraktionsfunktion als Wert enthält, sodass Sie den Wert zur Laufzeit an den entsprechenden Extraktor senden können.

using extractor = std::map<std::string, void(*)(boost::variable_value const&)>; 

oder

using extractor = std::map<std::string, 
          std::function<void(boost::variable_value const&)>; 

wenn Ihr Extraktoren komplizierter sind und nicht auf einen einfachen Funktionszeiger umwandeln. Ein Beispiel für einen Extraktor, der eine uint32_t drucken müssen, ist

auto extract_uint32_t = [](boost::variable_value const& v) { 
          std::cout << v.as<std::uint32_t>(); 
         }; 

Dann ist Ihre Schleife würde wie folgt aussehen:

for (const auto& it : vm) { 
    std::cout << it.first.c_str() << " " 
    extractor_obj[it.first](it.second) 
    std::cout << "\n"; 
} 

Hier ist ein live demo mit einigen Typen aus, aber es ist nahe genug, um Ihre Nutzung Fall, dass Sie in der Lage sein sollten, etwas Ähnliches anzuwenden.