قبول الزوجي السلبي مع Boost :: program_options
-
29-09-2019 - |
سؤال
أحتاج إلى أن أكون قادرًا على الحصول على boost::program_options
تحليل مجموعة من الزوجي التي يتم تمريرها على سطر الأوامر. بالنسبة للزوجي الإيجابي ، لا توجد مشكلة ، بالطبع (استخدم MultiToken std::vector<double>
في add_options) ، ولكن بالنسبة للسلبية ، أعرف أن هذه حجج غامضة.
إليكم مظاهرة لما أود أن أتناوله:
mycommand --extent -1.0 -2.0 -3.0 1.0 2.0 3.0 --some-other-argument somevalue
مدى هو أن تكون مدعومة من قبل أ Bounds
الفصل مع مُنشئ واحد على الأقل يأخذ ستة أفراد T
الحجج (في هذه الحالة - double
).
template <typename T>
class Bounds
{
public:
typedef T value_type;
typedef typename std::vector< Range<T> >::size_type size_type;
typedef typename std::vector< Range<T> > Ranges;
Bounds( T minx, T miny, T minz,
T maxx, T maxy, T maxz)
{
// fill Ranges vector
}
private:
Ranges ranges;
};
ما الذي يجب أن أقدمه لدعم استخدام Add_options في Bounds
صف دراسي؟ أود أن أفعل شيئًا مشابهًا لهذا. المستطاع؟
namespace po = boost::program_options;
po::options_description options("options");
options.add_options()
("extent,e", po::value< Bounds< double > >(), "Extent to clip points to")
po::variables_map vm;
po::store(po::command_line_parser(argc, argv).
options(options).positional(p).run(), vm);
po::notify(vm);
if (vm.count("extent"))
{
Bounds<double> bounds = vm["extent"].as< Bounds<double> >();
// do other stuff
}
المحلول
نهج التعامل مع الأرقام السلبية المحددة هنا قد تعمل أيضًا من أجلك.
كنت أجعله من قبل المحلل البسيط
store(command_line_parser(argc, argv).options(commands).run(), vm);
, ، لكن الحل كان لاستخدام الممتد:
parse_command_line
نصائح أخرى
الحيلة هي فرض boost
لتصنيف جميع الأرقام على أنها قيم موضعية (لا ينبغي الخلط بينها positional_options_description
. الطريقة التي تفعل بها هي تعريف أ style_parser
وأعطها ل command_line_parser
ك extra_style_parser
:
#include <boost/program_options/option.hpp>
#include <boost/lexical_cast/try_lexical_convert.hpp>
#include <boost/program_options/value_semantic.hpp>
using po = boost::program_options;
std::vector<po::option> ignore_numbers(std::vector<std::string>& args)
{
std::vector<po::option> result;
int pos = 0;
while(!args.empty()) {
const auto& arg = args[0];
double num;
if(boost::conversion::try_lexical_convert(arg, num)) {
result.push_back(po::option());
po::option& opt = result.back();
opt.position_key = pos++;
opt.value.push_back(arg);
opt.original_tokens.push_back(arg);
args.erase(args.begin());
} else {
break;
}
}
return result;
}
بمجرد الحصول عليها ، هذه هي الطريقة التي تستخدمها:
po::store(po::command_line_parser(argc, argv)
.extra_style_parser(&po::ignore_numbers)
.options(commands)
.run(), vm);
يمكنك الآن استخدام الأرقام السلبية ووسائط سطر الأوامر القصيرة في نفس الوقت.
ومع ذلك ، لا تزال هناك مشكلة ، لا توجد طريقة لتقييد عدد الرموز المميزة التي تتخذه كل حجة ، والتي قد تكون مشكلة إذا كنت تستخدم الوسائط الموضعية. على سبيل المثال ، لن ينجح شيء مثل هذا:
foo --coords 1 2 3 4 bar.baz
من أجل إصلاح هذا ، سنحتاج إلى إضافة طريقة لفرض عدد الرموز المميزة التي تتطلبها الوسيطة:
template<class T, class charT = char>
class bounded_typed_value : public po::typed_value<T, charT>
{
public:
bounded_typed_value(T* store_to)
: typed_value<T, charT>(store_to), m_min(-1), m_max(-1) {}
unsigned min_tokens() const {
if(m_min < 0) {
return po::typed_value<T, charT>::min_tokens();
} else {
return (unsigned)m_min;
}
}
unsigned max_tokens() const {
if(m_max < 0) {
return po::typed_value<T, charT>::max_tokens();
} else {
return (unsigned)m_max;
}
}
bounded_typed_value* min_tokens(unsigned min_tokens)
{
if(min_tokens > 1) {
po::typed_value<T, charT>::multitoken();
}
m_min = min_tokens;
return this;
}
bounded_typed_value* max_tokens(unsigned max_tokens)
{
if(max_tokens > 1) {
po::typed_value<T, charT>::multitoken();
}
m_max = max_tokens;
return this;
}
bounded_typed_value* fixed_tokens(unsigned num_tokens)
{
if(num_tokens > 1) {
po::typed_value<T, charT>::multitoken();
}
m_min = num_tokens;
m_max = num_tokens;
return this;
}
private:
int m_min;
int m_max;
};
template<class T, class charT = char>
bounded_typed_value<T, charT>*
bounded_value()
{
return new bounded_typed_value<T, charT>(0);
}
يمكنك الآن وضع كل شيء معًا مثل هذا:
po::positional_options_description p;
p.add("file-name", -1);
boost::program_options::options_description desc;
desc.add_options()
("coords,c", boost::program_options::bounded_value<vector<double>>()->fixed_tokens(4), "Bounding box");
po::store(po::command_line_parser(argc, argv)
.extra_style_parser(&po::ignore_numbers)
.positional(p)
.options(commands)
.run(), vm);
تتمثل الطريقة السهلة في لف المعلمات الخاصة بك في اقتباسات: myCommand-extent '-1.0 -2.0 -3.0 1.0 2.0 3.0'-some-argument somevalue