提升program_options自定义验证

时间:2017-04-23 15:14:20

标签: c++ validation boost

我正在尝试理解program_options自定义验证,以便将python代码转换为c ++代码 任何方式
我在示例中读到我必须重载验证功能
我试图在boost program_options文件中找到原始函数但是徒劳无功 任何人都可以告诉我原来的验证功能在哪里我会过载它 这是一个愚蠢的问题,但我想知道它是如何在默认情况下验证,以了解验证的概念及其如何完成 提前谢谢

1 个答案:

答案 0 :(得分:1)

扩展我的一行评论,我总是发现boost :: program_options在参数验证方面有点不足。

结果我发现为每种选项类型编写自定义类通常更容易。通常,program_options使用operator>>来解码选项值,因此如果重写此选项,您将有机会抛出program_options识别的异常。如果使用嵌套异常,则可以打印非常详细的错误诊断。

示例:

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

namespace po = boost::program_options;

// a custom option type
struct foo_or_bar {
    std::string value;

    // self-describing
    static constexpr const char *option_name() { return "foo"; }

    static constexpr const char *description() { return "single option only. value must be either foo or bar"; }

    // check the value and throw a nested exception chain if it's wrong    
    void check_value() const
    try {
        if (value != "foo" and value != "bar") {
            std::ostringstream ss;
            ss << "value must be foo or bar, you supplied " << std::quoted(value);
            throw std::invalid_argument(ss.str());
        }
    }
    catch (...) {
        std::throw_with_nested(po::validation_error(po::validation_error::invalid_option_value, option_name()));

    }

    // overload operators
    friend std::istream &operator>>(std::istream &is, foo_or_bar &arg) {
        is >> arg.value;
        arg.check_value();
        return is;
    }

    friend std::ostream &operator<<(std::ostream &os, foo_or_bar const &arg) {
        return os << arg.value;
    }

};

// test
void test(int argc, const char **argv) {
    foo_or_bar my_foo;

    po::options_description desc("test options");
    desc.add_options()
            (foo_or_bar::option_name(), po::value(&my_foo), foo_or_bar::description());

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


    std::cout << "foo is " << my_foo << std::endl;
}

void print_exception(const std::exception& e, int level =  0)
{
    std::cerr << std::string(level, ' ') << "exception: " << e.what() << '\n';
    try {
        std::rethrow_if_nested(e);
    } catch(const std::exception& e) {
        print_exception(e, level+1);
    } catch(...) {}
}

int main() {
    {
        std::vector<const char *> test_args = {
                "executable_name",
                "--foo=bar"
        };
        test(test_args.size(), test_args.data());
    }

    try {
        std::vector<const char *> test_args = {
                "executable_name",
                "--foo=bob"
        };
        test(test_args.size(), test_args.data());
    }
    catch (std::exception const &e) {
        print_exception(e);
    }
}

预期产出:

foo is bar
exception: the argument for option '--foo' is invalid
 exception: value must be foo or bar, you supplied "bob"