指定级别使用Boost program_options(例如--verbose) [英] Specifying levels (e.g. --verbose) using Boost program_options

查看:114
本文介绍了指定级别使用Boost program_options(例如--verbose)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的一些选项有多个层次,例如的冗长。
我想我的用户提供了以下两个等价的风格之间进行选择:

  //没有参数:1冗长
my_program -v//算'V的:4冗长
my_program -vv --something_else XYZ -vv//指定的值:4冗长
my_program --verbose 3

什么是使用Boost库program_options这样做的最简单的方法?


解决方案

这是怎么设想正在使用的code。


  1. 我们使用 LEVEL_VALUE级代替正常的 program_options的价值::

  2. 通过 option_level< CHAR>(your_value),其中 CHAR 是短选项字母,而 your_value 是可选的水平,例如,冗长,供给

示例

 的#include<升压/ program_options.hpp>
使用名字空间boost;
使用空间boost :: program_options;诠释的main()
{
    无符号的冗长= 0U;
    无符号something_else = 0U;    options_description递减(「购股权」);
    desc.add_options()
        (详细,V,
            LEVEL_VALUE级(option_level<'V'>(安培;冗长))
            在每一个额外的冗余级别打印更详细的消息。)
        (something_else,的,
            值<无符号>(安培; something_else);    返回0;
}

行为

 #冗长= 7
test_options -vvvvv --something_else 5 -vv3#覆盖冗长决赛
test_options -vvvvv --something_else 5 -v 7 -v 3#没有参数总是递增:冗长= 6
test_options -v --verbose 3 -v 5

实施

我们需要一些东西来支持水平:

<$p$p><$c$c>//________________________________________________________________________________________// t_option_level// ________________________________________________________________________________________
结构t_option_level {
上市:
    无符号N;
    明确t_option_level(无符号N_ = 0):N(_){}
    t_option_level&安培; INC {N + =由(由= 1无符号);返回*此;}
    t_option_level&安培;集(无符号VAL){N = VAL;返回*此;}
};模板&LT; typename的U&GT;
内嵌t_option_level * option_level(U * U)
{返回reinter pret_cast&LT; t_option_level *&GT;(U);}

递增或验证设置的值生命的逻辑:

 的#include&LT;升压/ program_options.hpp&GT;
#包括LT&;升压/ program_options / options_description.hpp&GT;
// ________________________________________________________________________________________
//
//验证
// ________________________________________________________________________________________
模板&LT;无符号SHORT_NAME&GT;
void验证(升压::任何和放大器; V,
              常量的std ::矢量&lt;标准::字符串&GT;&安培;值,
              t_option_level&LT;&SHORT_NAME GT; * / * * TARGET_TYPE /,INT)
{
    使用空间boost :: program_options;    //
    //获取当前值
    //
    t_option_level&LT;&SHORT_NAME GT;一世;
    如果(!v.empty())
        I =提振:: any_cast&LT; t_option_level&LT;&SHORT_NAME GT;&GT;(五);    //
    //提取任何参数
    //
    常量标准::字符串&安培; S =验证:: get_single_string(值true);
    如果(s.empty())
    {
        V =的boost ::任何(i.inc());
        返回;
    }    焦炭SHORT_NAME = SHORT_NAME;
    //多个值的
    如果(S ==标准::字符串(s.length(),SHORT_NAME))
    {
        V =的boost ::任何(i.inc(s.length()+ 1));
        返回;
    }    //匹配号码
    提高::正则表达式R(^(\\\\ D +)$);    //做正则表达式匹配和有趣的部分转换为
    // int类型。
    提高:: SMATCH什么;
    如果(regex_match(S,什么,R))
    {
        V =的boost ::任何(i.set(升压:: lexical_cast的&LT;无符号&GT;(S)));
        返回;
    }
    其他
    {
        扔VALIDATION_ERROR(VALIDATION_ERROR :: invalid_option_value,\\+ S +\\不是一个有效的论据。);
    }}

这提供了 program_options :: value_semantic 覆盖允许零个或一个参数:

 模板&LT; T类,类图=字符&GT;
类t_level_value:公众的boost :: program_options :: typed_value&LT; T,图表&GT;
{
上市:
    / **构造函数。在'store_to'参数告诉在哪里存储
        当它被称为价值。该参数可以为NULL。 * /
    t_level_value(T * store_to)
        :升压:: program_options :: typed_value&LT; T,图表&GT;(store_to)
    {}
    无符号min_tokens()const的
    {
        返回0;
    }    无符号max_tokens()const的
    {
        返回1;
    }
};模板&LT;类T&GT;
t_level_value&LT; T&GT; *
LEVEL_VALUE级(T * V)
{
    返回新t_level_value&LT; T&GT;(五);
}

Some of my options have multiple levels, e.g. of "verbosity". I would like my users to choose between the following two equivalent styles:

// no argument: verbosity of 1
my_program -v

// count the 'v's: verbosity of 4
my_program -vv --something_else XYZ -vv

// specify the value: verbosity of 4
my_program --verbose 3

What is the easiest way of doing this with the Boost program_options library?

解决方案

This is how I envisage the code being used.

  1. We use level_value in place of the normal program_options::value
  2. pass option_level<CHAR>(your_value) where CHAR is the short option letter, and your_value is the optional level, e.g. verbosity, being supplied

Example

#include <boost/program_options.hpp>
using namespace boost;
using namespace boost::program_options;

int main()  
{
    unsigned verbosity      = 0U;
    unsigned something_else = 0U;

    options_description desc("options");
    desc.add_options()
        ("verbose,v",               
            level_value(option_level<'v'>(&verbosity)),
            "Print more verbose messages at each additional verbosity level.")
        ("something_else,s",
            value<unsigned>(&something_else);

    return 0;
}

Behavior

# verbosity = 7
test_options -vvvvv --something_else 5 -vv

# final verbosity of 3 overrides
test_options -vvvvv --something_else 5 -v 7 -v 3

# no argument always increments: verbosity = 6
test_options -v 3 --verbose 5 -v

Implementation

We need something to hold the level:

//________________________________________________________________________________________

//  t_option_level

//________________________________________________________________________________________
struct t_option_level {
public:
    unsigned n;
    explicit t_option_level(unsigned n_ = 0):n(n_){}
    t_option_level& inc(unsigned by = 1){n += by; return *this;}
    t_option_level& set(unsigned val){n = val; return *this;}
};

template <typename U>
inline t_option_level* option_level(U* u)
{return reinterpret_cast<t_option_level*>(u);}

The logic to increment or set the value lives in the validator:

#include <boost/program_options.hpp>
#include <boost/program_options/options_description.hpp>
//________________________________________________________________________________________
// 
//      validate
//________________________________________________________________________________________
template <unsigned SHORT_NAME>
void validate(boost::any& v,
              const std::vector<std::string>& values,
              t_option_level<SHORT_NAME>* /*target_type*/, int)
{
    using namespace boost::program_options;

    // 
    // Get the current value
    // 
    t_option_level<SHORT_NAME> i;
    if (!v.empty())
        i = boost::any_cast<t_option_level<SHORT_NAME>>(v);

    //
    //  Extract any arguments 
    // 
    const std::string& s = validators::get_single_string(values, true);
    if (s.empty())
    {
        v = boost::any(i.inc());
        return;
    }

    char short_name = SHORT_NAME;
    // multiple 'values's
    if (s == std::string(s.length(), short_name))
    {
        v = boost::any(i.inc(s.length() + 1));
        return;
    }

    // match number
    boost::regex r("^(\\d+)$");

    // Do regex match and convert the interesting part to 
    // int.
    boost::smatch what;
    if (regex_match(s, what, r)) 
    {
        v = boost::any(i.set(boost::lexical_cast<unsigned>(s)));
        return;
    } 
    else 
    {
        throw validation_error(validation_error::invalid_option_value, "\"" + s + "\" is not a valid argument.");
    }        

}

This provides the program_options::value_semantic override to allow zero or one arguments:

template<class T, class charT = char>
class t_level_value : public boost::program_options::typed_value<T, charT>
{
public:
    /** Ctor. The 'store_to' parameter tells where to store
        the value when it's known. The parameter can be NULL. */
    t_level_value(T* store_to)
        : boost::program_options::typed_value<T, charT>(store_to)
    {} 
    unsigned min_tokens() const
    {
        return 0;
    }

    unsigned max_tokens() const 
    {
        return 1;
    }
};

template<class T>
t_level_value<T>*
level_value(T* v)
{
    return new t_level_value<T>(v);
}

这篇关于指定级别使用Boost program_options(例如--verbose)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆