3

私のオプションの中には、「冗長性」など、複数のレベルがあるものがあります。ユーザーに次の 2 つの同等のスタイルのいずれかを選択してもらいたい:

// 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

Boost program_options ライブラリでこれを行う最も簡単な方法は何ですか?

4

1 に答える 1

1

これは、使用されているコードを想定する方法です。

  1. level_value通常の代わりに使用しますprogram_options::value
  2. passoption_level<CHAR>(your_value)CHAR短いオプション文字で、your_valueはオプションのレベル (例: verbosity) です。

#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;
}

行動

# 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

実装

レベルを保持するために何かが必要です。

//________________________________________________________________________________________

//  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);}

値をインクリメントまたは設定するロジックは、バリデーターに存在します。

#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.");
    }        

}

これにより、program_options::value_semanticゼロまたは 1 つの引数を許可するオーバーライドが提供されます。

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);
}
于 2013-06-13T17:40:15.797 に答える