c++ - 覆盖boost中的验证方法不适用于样式集

标签 c++ boost

我正在尝试覆盖 validate boost::program_options 中的方法来解析一个点分的 ip 地址。我还需要在选项前只用一个破折号来解析参数。为此,我设置了标志 po::command_line_style::allow_slash_for_short。当我添加标志时,不会调用验证方法。如果我不设置它工作正常。有人可以指出问题或建议解决方法吗?

这是我的代码:

struct in_addr MCAST_ADDR;

void validate(boost::any& v, const std::vector<std::string>& values, in_addr* target_type, int)
{
    printf("validate\n");
    std::string const& mcast_addr = boost::program_options::validators::get_single_string(values);

    if (!mcast_addr.empty())
        if (inet_aton(mcast_addr.c_str(), &MCAST_ADDR) == 0) {
        fprintf(stderr, "Invalid address!\n");
    }
    v = boost::any(MCAST_ADDR);
}

namespace po = boost::program_options;

void parse_args(int argc, char *argv[]) {

    try
    {
        po::options_description desc("Options:");
        desc.add_options()
            ("help,h", "Help screen")
            ("a", po::value<in_addr>()->required(), "MCAST_ADDR");

        po::variables_map vm;
        po::store(po::command_line_parser(argc, argv)
                      .options(desc).
                      .style(po::command_line_style::allow_slash_for_short) /* the problematic line */
                      .run(), vm);

        po::notify(vm);

    }
    catch (const po::error &ex) {
        std::cerr << ex.what() << '\n';
    }
}

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

最佳答案

我认为普遍的问题是您的选项没有短名称。是的,“长名称”只是一个字符,但仍被认为是长名称。

要允许长选项伪装成短选项,请使用 allow_long_disguise .

接下来,要以任何方式允许短选项,您必须决定如何显示选项参数(--a=value- -一个值).

您会发现您未能做出此选择,因为有时该库会为您提供运行时诊断。例如:

.style(po::command_line_style::allow_long_disguise | po::command_line_style::allow_slash_for_short)

导致:

  • boost::program_options 配置错误:为长选项选择“command_line_style::long_allow_next”(空格分隔参数)或“command_line_style::long_allow_adja cent”(“=”分隔参数)中的一个。

现在,修复遗漏的最简单方法是仅基于默认行为:

.style(po::command_line_style::default_style
    | po::command_line_style::allow_long_disguise
    | po::command_line_style::allow_slash_for_short)

现在您可以传递大量选项:

./a.out /a 239.10.11.12
./a.out /a=239.10.11.12
./a.out -a 239.10.11.12
./a.out -a=239.10.11.12
./a.out --a 239.10.11.12
./a.out --a=239.10.11.12

全部打印

Parsed: 239.10.11.12

奖金

让我们使用 Boost 来解析和验证 IP 地址!

using ip_address = boost::asio::ip::address;

namespace boost { namespace asio { namespace ip {
    void validate(boost::any& v, const std::vector<std::string>& values, ip_address* /*target_type*/, int) {
        std::string const& mcast_addr = boost::program_options::validators::get_single_string(values);

        auto address = ip_address::from_string(mcast_addr);

        if (!address.is_multicast())
            throw std::invalid_argument("address not multicast: " + address.to_string());

        v = address;
    }
} } }

这样,如果我们传递一个非多播地址,我们会将其标记为错误并报告:

terminate called after throwing an instance of 'std::invalid_argument'
  what():  address not multicast: 240.10.11.12

完整演示

Live On Coliru

#include <boost/asio/ip/address.hpp>
#include <boost/program_options.hpp>
#include <iostream>

using ip_address = boost::asio::ip::address;

namespace boost { namespace asio { namespace ip {
    void validate(boost::any& v, const std::vector<std::string>& values, ip_address* /*target_type*/, int) {
        std::string const& mcast_addr = boost::program_options::validators::get_single_string(values);

        auto address = ip_address::from_string(mcast_addr);

        if (!address.is_multicast())
            throw std::invalid_argument("address not multicast: " + address.to_string());

        v = address;
    }
} } }

namespace po = boost::program_options;

int main(int argc, char *argv[])  try {
    po::options_description desc("Options:");
    desc.add_options()
        ("help,h", "Help screen")
        ("a", po::value<ip_address>()->required(), "MCAST_ADDR")
        ;

    po::variables_map vm;
    po::store(po::command_line_parser(argc, argv)
            .options(desc)
            .style(po::command_line_style::default_style
                | po::command_line_style::allow_long_disguise
                | po::command_line_style::allow_slash_for_short)
            .run(), vm);

    po::notify(vm);

    std::cout << "Parsed: " << vm["a"].as<ip_address>() << std::endl;

} catch (const po::error &ex) {
    std::cerr << ex.what() << std::endl;
}

其中还显示了所有测试用例:

+ ./a.out /a 239.10.11.12
Parsed: 239.10.11.12
+ ./a.out /a=239.10.11.12
Parsed: 239.10.11.12
+ ./a.out -a 239.10.11.12
Parsed: 239.10.11.12
+ ./a.out -a=239.10.11.12
Parsed: 239.10.11.12
+ ./a.out --a 239.10.11.12
Parsed: 239.10.11.12
+ ./a.out --a=239.10.11.12
Parsed: 239.10.11.12

+ ./a.out /a 240.10.11.12
terminate called after throwing an instance of 'std::invalid_argument'
  what():  address not multicast: 240.10.11.12
bash: line 11: 31582 Aborted                 (core dumped) ./a.out $options
+ ./a.out /a=240.10.11.12
terminate called after throwing an instance of 'std::invalid_argument'
  what():  address not multicast: 240.10.11.12
bash: line 11: 31585 Aborted                 (core dumped) ./a.out $options
+ ./a.out -a 240.10.11.12
terminate called after throwing an instance of 'std::invalid_argument'
  what():  address not multicast: 240.10.11.12
bash: line 11: 31587 Aborted                 (core dumped) ./a.out $options
+ ./a.out -a=240.10.11.12
terminate called after throwing an instance of 'std::invalid_argument'
  what():  address not multicast: 240.10.11.12
bash: line 11: 31589 Aborted                 (core dumped) ./a.out $options
+ ./a.out --a 240.10.11.12
terminate called after throwing an instance of 'std::invalid_argument'
  what():  address not multicast: 240.10.11.12

关于c++ - 覆盖boost中的验证方法不适用于样式集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50708068/

相关文章:

c++ - 如何在 Travis CI 中使用最新的 boost 版本?

c++ - 在Boost Graph Library中选择给定顶点的随机进出邻居的有效方法?

c++ - Boost wave上下文concept_check问题

c++ - boost::asio 异步服务器设计

c++ - 获取 streambuf/stringbuf 数据的所有权

java - 使用单个循环从数组中获取所有子数组

c++ - 可以从指向成员函数模板参数的指针推导出类类型吗

c++ - 将 boost::log 用于具有额外 'channel' 和 'id' 属性的多线程应用程序的最佳方法是什么

c++ - Windows SearchPath 函数

c++ - boost any library的典型用法是什么?