使用 boost::p rogram_options 指定多个标志

Use boost::program_options to specify multiple flags

本文关键字:标志 boost rogram 使用 options      更新时间:2023-10-16

我想使用 boost::p rogram_options 来指定所需的详细程度,这很常见。 例如

./test -v # verbosity = 1 
./test -vvv # verbosity = 3 
./test -v blah blah -v # verbosity = 2 

我知道如何多次出现需要值的选项,但我想要的是开关的多次出现。 单个开关可以通过类似的东西来完成

desc.add_options()
("verbosity,v", bool_switch(), "Increase verbosity");

但是,如果提供了多个 -V 选项,则此操作将失败并出现multiple_occurrences异常。

可以使用类似的东西完成多个布尔选项

desc.add_options()
("verbose,v", value<std::vector<int> >(), "Increase verbosity");

但这要求为每个选项赋予一个值,例如

./test -v 1 -v 1 -v 1

我遇到了这个确切的问题,并提出了以下内容。 希望它对某人有用,即使对于原始海报来说为时已晚。

#include "StdAfx.h"
#include <boostprogram_options.hpp>
#include <iostream>
namespace po = boost::program_options;
class CountValue : public po::typed_value<std::size_t>
{
public:
CountValue():
CountValue(nullptr)
{
}
CountValue(std::size_t* store):
po::typed_value<std::size_t>(store)
{
// Ensure that no tokens may be passed as a value.
default_value(0);
zero_tokens();
}
virtual ~CountValue()
{
}
virtual void xparse(boost::any& store, const std::vector<std::string>& /*tokens*/) const
{
// Replace the stored value with the access count.
store = boost::any(++count_);
}
private:
mutable std::size_t count_{ 0 };
};
int main(int argc, char** argv)
{
// Define the command line options (we create a new CountValue
// instance, on the understanding that it will be deleted for us
// when the options description instance goes out of scope).
po::options_description options("Options");
std::size_t verbose = 0;
options.add_options()
("verbose,v", new CountValue(&verbose), "Increase verbosity");
// Parse the command line options.
po::command_line_parser parser(argc, argv);
po::variables_map variables;
po::store(parser.options(options).run(), variables);
po::notify(variables);
// Show the verbosity level.
std::cout << "Verbosity " << verbose << "n";
}

这适用于 C++20 和 Boost 1.77。 这是在行动:

$ test
Verbosity 0
$ test -v
Verbosity 1
$ test -vvv
Verbosity 3
$ test -v blah blah -v
Verbosity 2

Huw Walters的回答對我非常有用。我已经对它进行了一些扩展,以允许通过数字参数明确设置详细级别。因此,所有这些调用都将详细程度设置为 4:

app -v -v -v -v
app -v4
app -vvvv
app -vvv -v
app -v3 -v

不幸的是,该解决方案的反制是,在-v后混合其他选项不起作用。因此,即使app -vx也是合法选择,x也会产生错误。

下面是代码。要使用它,请提供: ("verbose,v",新po_CountAndAddValue(&verbose(,"增加冗长"(; 作为add_options()的操作员。

class po_CountAndAddValue : public po::typed_value<std::size_t>
{
public:
po_CountAndAddValue(std::size_t* store)
: po::typed_value<std::size_t>(store)
{
default_value(0);
}
po_CountAndAddValue() : po_CountAndAddValue(nullptr) {}
~po_CountAndAddValue() override {}
// Allow zero or one tokens:
unsigned min_tokens() const override { return 0; }
unsigned max_tokens() const override { return 1; }
void xparse(boost::any& store,
const std::vector<std::string>& tokens) const override
{
if(tokens.empty()) {
count_++;
} else {
const std::string& tok = tokens[0];
if(std::all_of(tok.begin(), tok.end(), [](char c){return c=='v';})){
count_ += 1 + tok.size();
} else {
// Add explicitely specified verbosity count:
count_ += boost::lexical_cast<int>(tok);
}
}
// Replace the stored value with the updated access count:
store = boost::any(count_);
}
private:
mutable std::size_t count_{ 0 };
};

如果您不想允许混合使用带和不带数字参数的详细程度选项,则可以为这种情况添加错误报告,如下所示:

class po_CountOrSetValue : public po::typed_value<std::size_t>
{
public:
po_CountOrSetValue(std::size_t* store)
: po::typed_value<std::size_t>(store)
{
default_value(0);
}
po_CountOrSetValue() : po_CountOrSetValue(nullptr) {}
~po_CountOrSetValue() override {}
// Allow zero or one tokens:
unsigned min_tokens() const override { return 0; }
unsigned max_tokens() const override { return 1; }
class mixed_types_error : public po::error_with_option_name {
public:
mixed_types_error()
: po::error_with_option_name("option '%canonical_option%' wrongly used both with and without value"){}
~mixed_types_error() throw() {}
};
void xparse(boost::any& store,
const std::vector<std::string>& tokens) const override
{
if(tokens.empty() ||
std::all_of(tokens[0].begin(), tokens[0].end(),
[](char c){return c=='v';}))
{
if(set_) {
throw mixed_types_error();
}
count_ += tokens.empty() ? 1 : 1 + tokens[0].size();
} else {
if(std::exchange(set_, true)) {
throw po::multiple_occurrences();
}
if(count_ != 0) {
throw mixed_types_error();
}
count_ = boost::lexical_cast<int>(tokens[0]);
}
// Replace the stored value with the updated count:
store = boost::any(count_);
}
private:
mutable std::size_t count_{ 0 };
mutable bool set_{ false };
};

所有这些说明符都适用于第一个版本,将详细程度设置为 4,但在第二个版本中失败:

app -v3 -v
app -v3 -v1
app -vv -v2

一切都用 C++17 和 Boost 1.74 进行了测试。