опции программы boost: требует ли кастомный валидатор перегрузки оператора››?

В примере (regex.cpp ), автор библиотеки создал пользовательскую структуру (magic_number) и функцию проверки для этой структуры, чтобы показать, как пользовательскую структуру можно интегрировать в параметры программы. Я последовал его примеру, чтобы создать функцию проверки для пользовательского класса (MyClass). Компилятор жалуется, что lexical_cast недоступен для MyClass. Затем я реализовал std::istream& operator>>(std::istream& in, MyClass& d), удалил void validate(.., MyClass*, ..), код компилируется. Кто-нибудь может объяснить, почему в примере не требуется operator>>, а в моем не требуется validate?

РЕДАКТИРОВАТЬ:

#include <MyLib/MyClass.h>

std::istream& operator>>(std::istream& in, MyClass& obj) {
    // some code to populate obj
    return in;
}


po::variables_map parseCommandLine(int argc, char* argv[]) {

    po::options_description options("Options");
    options.add_options()
        ("help", "produce help message")
        ("obj", po::value<MyClass>(), "")
        ;
    po::variables_map vm;
    store(po::command_line_parser(argc, argv)
        .options(options).run(), vm);
    notify(vm);

    return vm;
}

int main(int argc, char* argv[]) {

    try {
        po::variables_map vm = parseCommandLine(argc, argv);

        MyClass obj = vm["my"].as<MyClass>();

        cout << obj << endl;
    } catch(std::exception& e) {
        cout << e.what() << "\n";
        return 1;
    }   
    return 0;
}
  • код компилируется без проверки.

Я также попытался внести минимальные изменения в regex.cpp:

  1. удалить magic_number
  2. добавить #include <MyLib/MyClass.h>
  3. замените все вхождения magic_number на MyClass.
  4. закомментируйте весь код в validate.
  5. Это не компилируется.

РЕДАКТИРОВАТЬ: добавить validate. Ни один из них не решил ошибку компилятора.

void validate(boost::any& v, 
              const std::vector<std::string>& values,
              std::vector<MyClass>*, int)
{
}

void validate(boost::any& v, 
              const std::vector<std::string>& values,
              MyClass*, long)
{
}

void validate(boost::any& v, 
              const std::vector<std::string>& values,
              MyClass*, int)
{      
}

РЕДАКТИРОВАТЬ: это может относиться к пространствам имен.

После того, как я окружил функцию проверки namespace boost { namespace program_options { }}, код скомпилировался без перегрузки op>>. Это также работает, если validate находится в том же пространстве имен, что и MyClass. Кто-нибудь может это объяснить?


person Candy Chiu    schedule 21.11.2012    source источник
comment
Можем ли мы посмотреть, как вы объявили свой объект program_options? Если проверки нет, невозможно проанализировать объект без op>>.   -  person J.N.    schedule 21.11.2012
comment
Это проблема компилятора. См. [описание проблемы здесь][1] [1]: stackoverflow.com/questions/13501598/   -  person Candy Chiu    schedule 22.11.2012


Ответы (1)


Основная проблема, с которой вы сталкиваетесь, заключается в том, что С++ не предлагает никаких средств для преобразования строки в произвольный пользовательский объект (я имею в виду без написания кода).

Чтобы решить эту проблему, program_options предлагает две возможности:

  • вы реализуете operator>>, который является стандартным способом C++ для этого, но который может повлиять на некоторые другие области (т. е. вы можете захотеть проанализировать свой объект определенным образом, кроме как в командной строке). Внутренне boost::lexical_cast используется для реализации преобразования и выдает ошибку, если op>> не найден.
  • вы реализуете функцию validate, специфичную для program_options, но не имеющую никакого влияния за пределами управления опциями.

Я предполагаю, что он использует метапрограммирование шаблонов, чтобы узнать, предоставили ли вы validate или по умолчанию будет lexical_cast.

Я не могу помочь вам, почему ваша попытка с validate не удалась, поскольку вы не предоставили для нее код.

Однако вот рабочий пример:

#include <boost/program_options.hpp>
#include <vector>
#include <string>

namespace po = boost::program_options;

namespace lib {
   class MyClass
    {
    public:
        int a;
    };

    void validate(boost::any& v,
                  const std::vector<std::string>& values,
                  MyClass*, int)
    {
        po::validators::check_first_occurrence(v);
        const string& s = po::validators::get_single_string(values);
        v = boost::any(MyClass { boost::lexical_cast<int>(s) } );
    }
}


po::variables_map parseCommandLine(int argc, char* argv[])
{
    po::options_description options("Options");
    options.add_options()
        ("help", "produce help message")
        ("obj", po::value<lib::MyClass>(), "")
        ;
    po::variables_map vm;
    store(po::command_line_parser(argc, argv)
        .options(options).run(), vm);
    notify(vm);

    return vm;
}

int main(int argc, char* argv[])
{
    try {
        po::variables_map vm = parseCommandLine(argc, argv);
        lib::MyClass obj = vm["obj"].as<lib::MyClass>();
        cout << obj.a << endl;
    } catch(std::exception& e) {
        cout << e.what() << "\n";
        return 1;
    }
    return 0;
}
  • Обновлять

При использовании пространства имен и класс, и проверка должны принадлежать одному и тому же пространству имен.

person J.N.    schedule 21.11.2012
comment
Дело в том, что программа НЕ компилировалась с пустой функцией проверки. Таким образом, создается впечатление, что компилятор каким-то образом не уловил перегрузку проверки и по умолчанию использовал lexical_cast. Кстати, ваш пример ничем не отличается от regex.cpp. - person Candy Chiu; 21.11.2012
comment
Вероятно, вы неправильно объявили свою функцию validate, но я не смогу помочь, если вы не покажете мне, как вы это сделали. Мой образец отлично компилируется с пустой проверкой. - person J.N.; 21.11.2012
comment
Я следил за подписями в boost/program_options/details/value_semantic.hpp. - person Candy Chiu; 21.11.2012
comment
не могли бы вы поместить MyClass в пространство имен, например, lib? - person Candy Chiu; 21.11.2012
comment
@CandyChiu Я обновил ответ, чтобы учесть пространство имен. - person J.N.; 22.11.2012
comment
Это конкретная проблема компилятора. Смотрите мои комментарии выше. - person Candy Chiu; 22.11.2012
comment
Намек на использование одного и того же пространства имен является точным. - person maxschlepzig; 19.01.2014
comment
Тот же аргумент сохраняется, когда ваш класс находится в пространстве имен std. В этом случае вы должны обернуть функцию validate внутри namespace std { ... } - person josch; 08.05.2020