2016-02-01 2 views
2

В настоящее время я работаю с boost::program_options. Моя программа должна принимать в качестве аргументов (среди прочего ...) произвольное количество «списков» произвольной длины. Например, пользователь должен иметь возможность вызватьC++: Boost program_options: Несколько списков аргументов

./myprogram -list item1 item2 item3 -list item1 item2 -list item1 item2 

Очевидно, что я не хочу, чтобы получить один список/вектор со всеми элементами, один за другим, в результате, но (в данном случае) три списка/векторы (или, например, один вектор векторов, содержащих элементы) с двумя или тремя элементами в списке (каждый элемент должен быть строкой, но я думаю, это не имеет значения). Как я уже говорил, количество списков (а также количество элементов в списке!) Должно быть произвольным. Как это сделать с помощью boost::program_options?

+2

AFAIK нет прямого пути сделайте это, так как каждый 'itemn' будет считаться индивидуальным вариантом. Одна вещь, которую вы можете сделать, это определить опцию «list», которая имеет тип «vector », а затем, когда вы передаете аргументы, передайте строку с разделителями, такую ​​как «-list» item1, item2, item3 «-list», item4, item5 "-list" item1, tem2 "' – Nim

+0

Хорошо, если нет другого способа, я бы подумал об этом, но я на самом деле думаю, что это очень сложно для пользователя и довольно неуравновешен. – DerAuenlaender

+1

Я уже пытался сделать что-то подобное раньше, но не удалось. Хотя параметры программы Boost очень приятны для более простых проблем, как только вы найдете прецедент или необходимость чего-то не поддерживаемого, вам в основном придется отказаться от него и написать собственную обработку аргументов командной строки. –

ответ

3

Это может быть сделано без большого количества дополнительного кода. Секрет состоит в том, чтобы отделить шаг анализа от этапа хранения, также как и в this answer.

Парсер вернет контейнер с ключами/значениями, поскольку параметры представлены от пользователя. Если параметр передается несколько раз, тогда у контейнера будет отдельная запись для каждой подачи параметра. Очень просто отсканировать конкретный вариант и упорядочить его значения, но мы хотим.

Вот пример, который печатает каждый входной мульти-токены варианта на отдельную строку:

#include <iostream> 
#include <string> 
#include <vector> 

#include <boost/program_options.hpp> 

namespace po = boost::program_options; 

int main(int argc, char *argv[]) { 
    // Define a multi-token option. 
    po::options_description desc("Allowed options"); 
    desc.add_options() 
     ("list", po::value<std::vector<std::string>>()->multitoken(), "multiple values"); 

    // Just parse the options without storing them in a map. 
    po::parsed_options parsed_options = po::command_line_parser(argc, argv) 
     .options(desc) 
     .run(); 

    // Build list of multi-valued option instances. We iterate through 
    // each command-line option, whether it is repeated or not. We 
    // accumulate the values for our multi-valued option in a 
    // container. 
    std::vector<std::vector<std::string>> lists; 
    for (const po::option& o : parsed_options.options) { 
     if (o.string_key == "list") 
     lists.push_back(o.value); 
    } 

    // If we had other normal options, we would store them in a map 
    // here. In this demo program it isn't really necessary because 
    // we are only interested in our special multi-valued option. 
    po::variables_map vm; 
    po::store(parsed_options, vm); 

    // Print out the multi-valued option, each separate instance on its 
    // own line. 
    for (size_t i = 0; i < lists.size(); ++i) { 
     for (size_t j = 0; j < lists[i].size(); ++j) 
     std::cout << lists[i][j] << ' '; 
     std::cout << '\n'; 
    } 

    return 0; 
} 

А вот пример вызов (live at coliru):

$ ./po --list 1 2 3 --list foo bar --list how now brown cow 
1 2 3 
foo bar 
how now brown cow 
Смежные вопросы