我正在尝试覆盖 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
完整演示
#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/