Обрабатывать параметр без значения в файле конфигурации в Boost program_options


person abhishek gupta    schedule 11.05.2020    source источник
comment
Не мешало бы показать пример кода и конфиг. Сейчас людям придется придумывать это с нуля.   -  person sehe    schedule 11.05.2020
comment
@sehe Ссылка на вопрос содержит код, а также пример конфигурации.   -  person abhishek gupta    schedule 11.05.2020


Ответы (1)


ОБНОВЛЕНИЕ Первоначальный ответ дал неверное представление. Вот обновление.

Итак, вы хотите, чтобы foo= (без значения) вел себя так, как будто этой строки даже не было в конфигурации.

Это означает, что семантика значений по умолчанию (то есть то, что происходит при уведомлении, которое переносит состояние из компонента синтаксического анализатора в компонент хранилища) не очень хороша.

Вы можете преодолеть это, изобретя свою собственную семантику значений (mybool_switch, так сказать) или согласившись на value<my_particulat_bool>, где вы добавляете потоковые операции, чтобы параметр вел себя так, как вы хотите. Другими словами, стреляя из канона в муху.

Однако намного проще было бы вмешаться на этапе синтаксического анализатора, изменив parsed_options перед notify().

Вот довольно полная иллюстрация с живой демонстрацией:

Жить на Coliru

#include <boost/program_options/config.hpp>
#include <boost/program_options.hpp>
#include <iostream>
#include <iomanip>

namespace po = boost::program_options;

int main() {
    po::options_description desc;
    desc.add_options()
        ("foo", po::bool_switch())
        ("bar", po::bool_switch()->default_value(false))
        ("qux", po::bool_switch()->implicit_value(false))
        ;

    std::set<std::string> const bool_switches {"foo", "bar", "qux" };

    for (std::string contents :
            { "", "foo=", "foo=true", 
                  "bar=", "bar=true", 
                  "qux=", "qux=true"})
    {
        std::istringstream iss(contents);
        po::parsed_options parsed = po::parse_config_file(iss, desc, false);

        std::cout << "\n---\n" << std::quoted(contents) << "\n";

        // the magic is here:
        for (auto it = parsed.options.begin(); it!= parsed.options.end();) {
            using V = std::vector<std::string>;
            V const& v = it->value;
            if (bool_switches.count(it->string_key) && (v==V{} || v==V{""})) {
                std::cout << "*** Discarding config key without a value: " << it->string_key << "\n";
                it = parsed.options.erase(it);
            } else {
                ++it;
            }
        }

        po::variables_map vm;
        po::store(parsed, vm);

        for (auto& key : bool_switches) {
            auto& entry = vm[key];
            std::cout << " " << key << " ->" << std::boolalpha
                << (entry.empty()?" .empty()":"")    
                << (entry.defaulted()?" .defaulted()":"");
            if (entry.empty())
                std::cout << " (no value)\n";
            else
                std::cout << " value:" << entry.as<bool>() << "\n";
        }
    }
}

Который будет печатать

---
""
 bar -> .defaulted() value:false
 foo -> .defaulted() value:false
 qux -> .defaulted() value:false

---
"foo="
*** Discarding config key without a value: foo
 bar -> .defaulted() value:false
 foo -> .defaulted() value:false
 qux -> .defaulted() value:false

---
"foo=true"
 bar -> .defaulted() value:false
 foo -> value:true
 qux -> .defaulted() value:false

---
"bar="
*** Discarding config key without a value: bar
 bar -> .defaulted() value:false
 foo -> .defaulted() value:false
 qux -> .defaulted() value:false

---
"bar=true"
 bar -> value:true
 foo -> .defaulted() value:false
 qux -> .defaulted() value:false

---
"qux="
*** Discarding config key without a value: qux
 bar -> .defaulted() value:false
 foo -> .defaulted() value:false
 qux -> .defaulted() value:false

---
"qux=true"
 bar -> .defaulted() value:false
 foo -> .defaulted() value:false
 qux -> value:true
person sehe    schedule 11.05.2020
comment
Гах, снова прочитав ваш вопрос, я задаюсь вопросом, действительно ли это была ваша проблема (помогает, если вы откровенны). Возможно, вы искали это: coliru.stacked-crooked.com/a/4ccb762029649112 - person sehe; 11.05.2020
comment
Если это не, то, несомненно, вам нужно манипулировать parsed_options промежуточным звеном перед уведомлением. Вот хороший учебник по интерфейсу: - person sehe; 11.05.2020
comment
Сделал это Жить на Coliru. Дайте мне знать, если это был ответ, я могу обновить текст, чтобы отразить его. Обязательно прочитайте ранее связанный ответ о обосновании этого решения. - person sehe; 11.05.2020
comment
Перебор проанализированных параметров перед их сохранением кажется действительно хорошим решением для этого. Спасибо большое :). Просто хотел подтвердить, что использование bool_switch(), default_value() и implicit_value() не имеет отношения к решению. - person abhishek gupta; 11.05.2020
comment
Да. Я считаю, что эти вещи должны охватывать все варианты, потому что вопрос не указывался, и было уже сложно получить точную цель. Рад помочь. Обновил (заменил) ответ. - person sehe; 11.05.2020