سؤال

أحتاج إلى أن أكون قادرًا على الحصول على 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

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top