يمكن أن تعزز برنامج _options قيم الوسيطة المنفصلة فاصلة منفصلة
-
28-09-2019 - |
سؤال
إذا كان سطر الأوامر الخاص بي هو:
> prog --mylist=a,b,c
يمكن إعداد برنامج _POTIONS لزيادة ثلاث قيم وسيطة مميزة لـ mylist
جدال؟ لقد قمت بتكوين program_options على النحو التالي:
namespace po = boost::program_options;
po::options_description opts("blah")
opts.add_options()
("mylist", std::vector<std::string>>()->multitoken, "description");
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, opts), vm);
po::notify(vm);
عندما أتحقق من قيمة mylist
الحجة ، أرى قيمة واحدة a,b,c
. أود أن أرى ثلاث قيم متميزة ، انقسام على الفاصلة. هذا يعمل بشكل جيد إذا قمت بتحديد سطر الأوامر على النحو التالي:
> prog --mylist=a b c
أو
> prog --mylist=a --mylist=b --mylist=c
هل هناك طريقة لتكوين program_options بحيث ترى a,b,c
كثلاث قيم يجب إدراج كل منها في المتجه ، بدلاً من واحدة؟
أنا أستخدم Boost 1.41 ، G ++ 4.5.0 20100520 ، وقد مكنت الامتدادات التجريبية C ++ 0x.
تعديل:
يعمل الحل المقبول ولكن ينتهي به الأمر إلى أن يكون أكثر تعقيدًا ، IMO ، من التكرار من خلال ناقل وتقسيم القيم يدويًا. في النهاية ، اتخذت اقتراحًا من جيمس ماكنليس ونفذته بهذه الطريقة. لم يتم تقديم حله كإجابة ، ومع ذلك ، قبلت الحل الصحيح الآخر من Hkaiser. كلاهما عمل ، لكن الرمز اليدوي أكثر وضوحًا.
المحلول
يمكنك تسجيل مصلحة مخصصة لخيارك:
namespace po = boost::program_options;
struct mylist_option
{
// values specified with --mylist will be stored here
vector<std::string> values;
// Function which validates additional tokens from command line.
static void
validate(boost::any &v, std::vector<std::string> const &tokens)
{
if (v.empty())
v = boost::any(mylist_option());
mylist_option *p = boost::any_cast<mylist_option>(&v);
BOOST_ASSERT(p);
boost::char_separator<char> sep(",");
BOOST_FOREACH(std::string const& t, tokens)
{
if (t.find(",")) {
// tokenize values and push them back onto p->values
boost::tokenizer<boost::char_separator<char> > tok(t, sep);
std::copy(tok.begin(), tok.end(),
std::back_inserter(p->values));
}
else {
// store value as is
p->values.push_back(t);
}
}
}
};
الذي يمكن استخدامه بعد ذلك:
opts.add_options()
("mylist", po::value<mylist_option>()->multitoken(), "description");
و:
if (vm.count("mylist"))
{
// vm["mylist"].as<mylist_option>().values will hold the value specified
// using --mylist
}
نصائح أخرى
لم أحاول القيام بذلك بنفسي ، ولكن ربما تكون قادرًا على استخدام نفس النهج كما في مثال Custom_syntax.cp program_options
, ، لكتابة المحلل الخاص بك والتي يمكنك توفيرها كحوض إضافي. هناك القليل من المعلومات هنا مع مثال قصير. ثم يمكنك إما الجمع بين ذلك مع اقتراح جيمس باستخدام Boost :: Tokenizer ، أو مجرد اتباع اقتراحه.
هذا ما أستخدمه الآن:
template<typename T, int N> class mytype;
template<typename T, int N> std::istream& operator>> (std::istream& is, mytype<T,N>& rhs);
template<typename T, int N> std::ostream& operator<< (std::ostream& os, const mytype<T,N>& rhs);
template < typename T, int N >
struct mytype
{
T values[N];
friend std::istream& operator>> <>(std::istream &is, mytype<T,N> &val);
friend std::ostream& operator<< <>(std::ostream &os, const mytype<T,N> &val);
};
template<typename T, int N>
inline std::istream& operator>>(std::istream &is, mytype<T,N> &val)
{
for( int i = 0; i < N; ++i )
{
if( i )
if (is.peek() == ',')
is.ignore();
is >> val.values[i];
}
return is;
}
template<typename T, int N>
inline std::ostream& operator<<(std::ostream &os, const mytype<T,N> &val)
{
for( int i = 0; i < N; ++i )
{
if( i ) os << ',';
os << val.values[i];
}
return os;
}
int main(int argc, char *argv[])
{
namespace po = boost::program_options;
typedef mytype<int,2> mytype; // let's test with 2 int
mytype my;
try
{
po::options_description desc("the desc");
desc.add_options()
("mylist", po::value< mytype >(&my), "mylist desc")
;
po::variables_map vm;
po::store(po::command_line_parser(argc, argv).options(desc).run(), vm);
po::notify(vm);
if (vm.count("mylist"))
{
const mytype ret = vm["mylist"].as<mytype >();
std::cerr << "mylist: " << ret << " or: " << my << std::endl;
}
}
catch(std::exception& e)
{
std::cout << e.what() << "\n";
}
return 0;
}