7

boost :: program_optionsを使用して、次のように呼び出すことができる実行可能ファイルを作成したいと思います。

./example --nmax=0,10  # nmax is chosen randomly between 0 and 10
./example --nmax=9     # nmax is set to 9
./example              # nmax is set to the default value of 10

最小限のコードで、タイプセーフな方法でこれを達成するための最良の方法は何ですか?

4

4 に答える 4

4

boost :: program_optionsを使用して、次のように呼び出すことができる実行可能ファイルを作成したいと思います。

ライブラリは非常に柔軟性があり、program_optionsストリームの挿入および抽出演算子を使用して独自のクラスを作成することで、これを簡単にサポートできます。

#include <iostream>
#include <limits>
#include <stdlib.h>

#include <boost/lexical_cast.hpp>
#include <boost/program_options.hpp>


class Max
{
public:
    Max() :
        _max( std::numeric_limits<int>::max() )
    {

    }

    Max(
            int max
       ) :
        _max( max )
    {

    }

    Max(
            int low,
            int high
       )
    {
        int value = rand();
        value %= (high - low);
        value += low;
        _max = value;
    }

    int value() const { return _max; }

private:     
    int _max;
};

std::ostream&
operator<<(
        std::ostream& os,
        const Max& foo
        )
{
    os << foo.value();
    return os;
}

std::istream&
operator>>(
        std::istream& is,
        Max& foo
        )
{
    std::string line;
    std::getline( is, line );
    if ( !is ) return is;

    const std::string::size_type comma = line.find_first_of( ',' );
    try {
        if ( comma != std::string::npos ) {
            const int low = boost::lexical_cast<int>( line.substr(0, comma) );
            const int high = boost::lexical_cast<int>( line.substr(comma + 1) );
            foo = Max( low, high );
        } else {
            foo = Max( boost::lexical_cast<int>(line) );
        }
    } catch ( const boost::bad_lexical_cast& e ) {
        std::cerr << "garbage when convering Max value '" << line << "'" << std::endl;

        is.setstate( std::ios::failbit );
    }

    return is;
}

int
main( int argc, char** argv )
{
    namespace po = boost::program_options;

    Max nmax;

    po::options_description options;
    options.add_options()
        ("nmax", po::value(&nmax)->default_value(10), "random number range, or value" )
        ("help,h", po::bool_switch(), "help text")
        ;

    po::variables_map vm;
    try {
        po::command_line_parser cmd_line( argc, argv );
        cmd_line.options( options );
        po::store( cmd_line.run(), vm );
        po::notify( vm );
    } catch ( const boost::program_options::error& e ) {
        std::cerr << e.what() << std::endl;
        exit( EXIT_FAILURE );
    }

    if ( vm["help"].as<bool>() ) {
        std::cout << argv[0] << " [OPTIONS]" << std::endl;
        std::cout << std::endl;
        std::cout << "OPTIONS:" << std::endl;
        std::cout << options << std::endl;
        exit(EXIT_SUCCESS);
    }

    std::cout << "random value: " << nmax.value() << std::endl;
}

サンプルセッション

samm:stackoverflow samm$ ./a.out
random value: 10
samm:stackoverflow samm$ ./a.out --nmax 55
random value: 55
samm:stackoverflow samm$ ./a.out --nmax 10,25
random value: 17
samm:stackoverflow samm$ 
于 2012-04-16T15:42:47.033 に答える
1

ライブラリは、あなたが提案するような「多態的な」引数タイプを提供していません。各引数には、正確に1つのタイプがあります。引数の構文に基づいて異なる値を設定する場合は、その機能を自分で追加する必要があります。

簡単な方法は、Kerrekのコメントが示唆しているように文字列を使用して実行し、後でそれを解析することです。それほど多くのコードは必要ありません。

別の方法は、カスタムバリデーターを使用することです。この形式の引数専用の特殊な型を作成してから、validate文字列値をカスタム型の値に変換する関数を記述します。検証が失敗した場合は例外をスローします。Program_Optionsライブラリは、組み込み型の検証の失敗と同じように扱います。別の質問に答えて、バリデーターの例を書きました。

このために作成するコードは、コマンドラインを解析した後に文字列を解析するために作成するコードとほぼ同じです。それを引数型に組み込むか、後で処理するかが問題になります。

于 2012-04-16T15:04:52.483 に答える
1

私はこのコードをここに投稿しています。誰かに役立つことを願っています。これは、SamMillerの回答の「テンプレート化された」バージョンです。

#ifndef RANDOMCONSTANT_HH
#define RANDOMCONSTANT_HH

#include <boost/random.hpp>

boost::random::mt19937 g_randomConstantPrng(static_cast<unsigned int>(std::time(NULL) + getpid()));

template<typename T>
class RandomConstant
{
public:
    RandomConstant() { /* nothing */ }
    RandomConstant(T value) : _value(value) { /* nothing */ }
    RandomConstant(int low, int high)
    {
        boost::random::uniform_int_distribution<> dist(low, high);
        _value = dist(g_randomConstantPrng);
    }
    RandomConstant(double low, double high)
    {
        boost::random::uniform_real_distribution<> dist(low, high);
        _value = dist(g_randomConstantPrng);
    }
    T value() const { return _value; }

private:
    T _value;
};


template<typename T>
std::ostream&
operator<<(std::ostream& os, const RandomConstant<T>& foo)
{
    os << foo.value();
    return os;
}

template<typename T>
std::istream&
operator>>(std::istream &is, RandomConstant<T> &foo)
{
    std::string line;
    std::getline(is, line);
    if (!is) return is;

    const std::string::size_type comma = line.find_first_of( ',' );
    if (comma != std::string::npos)
    {
        const T low = boost::lexical_cast<T>( line.substr(0, comma) );
        const T high = boost::lexical_cast<T>( line.substr(comma + 1) );
        foo = RandomConstant<T>(low, high);
    }
    else
    {
        foo = RandomConstant<T>(boost::lexical_cast<T>(line));
    }

    return is;
}

#endif /* RANDOMCONSTANT_HH */

次のように使用されます。

namespace po = boost::program_options;
po::options_description desc;
desc.add_options()
    ("help", "show help")
    ("intValue", po::value<RandomConstant<int>>()->default_value(3), "description 1")
    ("doubleValue", po::value<RandomConstant<double>>()->default_value(1.5), "description 2")
;

po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
po::notify(vm);

if (vm.count("help")) {
    std::cerr << desc << std::endl;
    return EXIT_FAILURE;
}

int intValue = vm["intValue"].as<RandomConstant<int>>().value();
double doubleValue = vm["doubleValue"].as<RandomConstant<double>>().value();
于 2012-04-17T08:14:48.570 に答える
0

おそらくマルチトークンを使用できます

po::options_description desc("Allowed options");
desc.add_options()
    ("nmax", po::value< std::vector< float > >()->multitoken()->default_value(10), "description")
;

...

float value;
if (vm.count["nmax"] == 2)
    value = random value ...
else
    value = vm["nmax"].as< std::vector< float > >()[0];
于 2013-04-18T05:19:14.970 に答える