C++: Boost program_options: Несколько списков аргументов

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

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

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


person DerAuenlaender    schedule 01.02.2016    source источник
comment
Насколько я знаю, прямого способа сделать это нет, так как каждый itemn будет считаться отдельным вариантом. Одна вещь, которую вы можете сделать, это определить параметр, называемый списком, который имеет тип vector<string>, а затем, когда вы передаете аргументы, передаете строку с разделителями, например -list "item1,item2,item3" -list "item4,item5" -list "item1,tem2"   -  person Nim    schedule 01.02.2016
comment
Хорошо, если действительно нет другого способа, я бы подумал о том, чтобы сделать это таким образом, но я действительно думаю, что это очень сложно для пользователя и довольно неэлегантно.   -  person DerAuenlaender    schedule 01.02.2016
comment
Я пытался сделать что-то подобное раньше, но не удалось. В то время как параметры программы Boost очень хороши для более простых задач, как только вы обнаружите вариант использования или потребность в чем-то, что не поддерживается, вам в основном придется отказаться от этого и написать свою собственную обработку аргументов командной строки.   -  person Some programmer dude    schedule 01.02.2016


Ответы (1)


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

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

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

#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;
}

А вот пример вызова (по адресу coliru):

$ ./po --list 1 2 3 --list foo bar --list how now brown cow
1 2 3 
foo bar 
how now brown cow 
person rhashimoto    schedule 05.02.2016