Подтвердить что ты не робот

Обработка сложных опций с помощью Boost program_options

У меня есть программа, которая генерирует графики с использованием разных многоуровневых моделей. Каждая многоуровневая модель состоит из поколения меньшего семенного графа (например, 50 узлов), который может быть создан из нескольких моделей (например, для каждого возможного края, выберите его включение с вероятностью p).

После генерации семенного графа график расширяется до более крупного (например, 1000 узлов), используя один из других наборов моделей.

В каждом из двух этапов каждая модель требует другого количества параметров.

Я бы хотел, чтобы функции program_options анализировали различные возможные параметры, в соответствии с названиями моделей.

Например, скажем, у меня есть две модели семенных графов: SA, у которой есть 1 параметр, и SB, у которого два. Также для части расширения у меня есть две модели: A и B, опять же с 1 и 2 параметрами, соответственно. Я хотел бы иметь возможность сделать что-то вроде:

./graph_generator --seed=SA 0.1 --expansion=A 0.2
./graph_generator --seed=SB 0.1 3 --expansion=A 0.2
./graph_generator --seed=SA 0.1 --expansion=B 10 20
./graph_generator --seed=SB 0.1 3 --expansion=B 10 20

и корректно проанализируйте параметры. Возможно ли это?

4b9b3361

Ответ 1

Используя пользовательский валидатор и boost:: program_options:: значение:: multitoken, вы можете достичь желаемого результата:

#include <iostream>
#include <boost/lexical_cast.hpp>
#include <boost/optional.hpp>
#include <boost/program_options.hpp>

// Holds parameters for seed/expansion model
struct Model
{
    std::string type;
    boost::optional<float> param1;
    boost::optional<float> param2;
};

// Called by program_options to parse a set of Model arguments
void validate(boost::any& v, const std::vector<std::string>& values,
              Model*, int)
{
    Model model;
    // Extract tokens from values string vector and populate Model struct.
    if (values.size() == 0)
    {
        throw boost::program_options::validation_error(
            "Invalid model specification");
    }
    model.type = values.at(0); // Should validate for A/B
    if (values.size() >= 2)
        model.param1 = boost::lexical_cast<float>(values.at(1));
    if (values.size() >= 3)
        model.param2 = boost::lexical_cast<float>(values.at(2));

    v = model;
}

int main(int argc, char* argv[])
{
    Model seedModel, expansionModel;

    namespace po = boost::program_options;
    po::options_description options("Generic options");
    options.add_options()
        ("seed",
             po::value<Model>(&seedModel)->multitoken(),
             "seed graph model")
        ("expansion",
             po::value<Model>(&expansionModel)->multitoken(),
             "expansion model")
        ;

    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, options), vm);
    po::notify(vm);

    std::cout << "Seed type: " << seedModel.type << "\n";
    if (seedModel.param1)
        std::cout << "Seed param1: " << *(seedModel.param1) << "\n";
    if (seedModel.param2)
        std::cout << "Seed param2: " << *(seedModel.param2) << "\n";

    std::cout << "Expansion type: " << expansionModel.type << "\n";
    if (expansionModel.param1)
        std::cout << "Expansion param1: " << *(expansionModel.param1) << "\n";
    if (expansionModel.param2)
        std::cout << "Expansion param2: " << *(expansionModel.param2) << "\n";

    return 0;
}

Функция validate, вероятно, нуждается в большей строгости, но вы получите эту идею.

Это компилируется и работает для меня.