[program options] optional/required options

Hi, I don't know if this has been answered yet, but is there any concept of optional/required options in the program option library? Currently, only "allowed options" can be defined, no? I would be great if you could define different sets of required option groups (because it's possible that a+b _or_ a+c are required) and provide some validatation for that. Otherwise, you have to do that by hand again and again. Stefan

Hi Stefan,
I don't know if this has been answered yet, but is there any concept of optional/required options in the program option library?
No; the "required options" functionality was requested, though.
Currently, only "allowed options" can be defined, no?
I would be great if you could define different sets of required option groups (because it's possible that a+b _or_ a+c are required) and provide some validatation for that. Otherwise, you have to do that by hand again and again.
Can you give the specific use cases. I think that fully generic solution can be overly complex, and we can get away with some helper functions. Say, 'mutially_excluse_options' can check than only one option of a group is specified. - Volodya

Vladimir Prus wrote:
Can you give the specific use cases. I think that fully generic solution can be overly complex, and we can get away with some helper functions. Say, 'mutially_excluse_options' can check than only one option of a group is specified.
what about this syntax? po::options_validator v = ( po::exists("option_a") & po::exists("option_c") | ( po::exists("option_c") & po::exists("option_d") ; bool valid = v.validate(desc); I attach a working basic solution (many things copied from spirit ;) ), feel free to do anything you want with it. I used operator ^ for mutually exclusive options, but I'm afraid it's not perfect as it's not the same as xor! Cheers, Stefan #ifndef VALIDATOR_H_INCLUDED #define VALIDATOR_H_INCLUDED // Copyright Stefan Slapeta 2005. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) #include <boost/shared_ptr.hpp> #include <boost/compressed_pair.hpp> #include <boost/program_options/options_description.hpp> namespace boost { namespace program_options { template <typename DerivedT> class validator_base { public: bool validate(options_description const& desc) const { return derived().do_validate(desc); } DerivedT const& derived() const { return *static_cast<DerivedT const*>(this); } DerivedT& derived() { return *static_cast<DerivedT*>(this); } }; template <typename L, typename R, typename BaseT> class binary_validator : public BaseT { public: typedef typename boost::call_traits<L>::param_type left_param_t; typedef typename boost::call_traits<L>::const_reference left_return_t; typedef typename boost::call_traits<R>::param_type right_param_t; typedef typename boost::call_traits<R>::const_reference right_return_t; typedef typename boost::remove_reference<L>::type left_embed_t; typedef typename boost::remove_reference<R>::type right_embed_t; binary_validator(left_param_t left, right_param_t right) : m_subj(left, right) { } left_return_t left() const { return m_subj.first(); } right_return_t right() const { return m_subj.second(); } private: boost::compressed_pair<left_embed_t, right_embed_t> m_subj; }; template <typename L, typename R> class exists_composite : public binary_validator<L, R, validator_base<exists_composite<L, R> > > { public: typedef exists_composite<L, R> self_t; typedef binary_validator<L, R, validator_base<self_t> > base_t; exists_composite(L const& left, R const& right) : base_t(left, right) { } bool do_validate(options_description const& desc) const { return left().validate(desc) && right().validate(desc); } }; template <typename L, typename R> class exists_alternative : public binary_validator<L, R, validator_base<exists_alternative<L, R> > > { public: typedef exists_alternative<L, R> self_t; typedef binary_validator<L, R, validator_base<self_t> > base_t; exists_alternative(L const& left, R const& right) : base_t(left, right) { } bool do_validate(options_description const& desc) const { return left().validate(desc) || right().validate(desc); } }; template <typename L, typename R> class mutually_exclusive : public binary_validator<L, R, validator_base<mutually_exclusive<L, R> > > { public: typedef mutually_exclusive<L, R> self_t; typedef binary_validator<L, R, validator_base<self_t> > base_t; mutually_exclusive(L const& left, R const& right) : base_t(left, right) { } bool do_validate(options_description const& desc) const { return left().validate(desc) || right().validate(desc); } }; class exists : public validator_base<exists> { public: exists(std::string const& option) : m_option(option) { } bool do_validate(options_description const& desc) const { return desc.count(m_option) != 0; } private: std::string m_option; }; template <typename LeftValidatorT, typename RightValidatorT> exists_alternative<LeftValidatorT, RightValidatorT> operator | (validator_base<LeftValidatorT> const& l, validator_base<RightValidatorT> const& r) { return exists_alternative<LeftValidatorT, RightValidatorT>(l.derived(), r.derived()); } template <typename LeftValidatorT, typename RightValidatorT> exists_composite<LeftValidatorT, RightValidatorT> operator & (validator_base<LeftValidatorT> const& l, validator_base<RightValidatorT> const& r) { return exists_composite<LeftValidatorT, RightValidatorT>(l.derived(), r.derived()); } template <typename LeftValidatorT, typename RightValidatorT> mutually_exclusive<LeftValidatorT, RightValidatorT> operator ^ (validator_base<LeftValidatorT> const& l, validator_base<RightValidatorT> const& r) { return mutually_exclusive<LeftValidatorT, RightValidatorT>(l.derived(), r.derived()); } class validator_impl_base { public: bool validate(options_description const& desc) const { return validate_virtual(desc); } private: virtual bool validate_virtual(options_description const& desc) const = 0; }; template <typename ValidatorT> class validator_impl : public validator_impl_base { public: validator_impl(ValidatorT const& v) : m_validator(v) { } private: bool validate_virtual(options_description const& desc) const { return m_validator.validate(desc); } ValidatorT m_validator; }; class options_validator { public: template <typename ValidatorT> options_validator(validator_base<ValidatorT> const& v) : m_validator(new validator_impl<ValidatorT>(v.derived())) { } bool validate(options_description const& desc) const { return m_validator->validate(desc); } private: boost::shared_ptr<validator_impl_base> m_validator; }; }} #endif

Stefan Slapeta wrote:
Vladimir Prus wrote:
Can you give the specific use cases. I think that fully generic solution can be overly complex, and we can get away with some helper functions. Say, 'mutially_excluse_options' can check than only one option of a group is specified.
what about this syntax?
po::options_validator v = ( po::exists("option_a") & po::exists("option_c") | ( po::exists("option_c") & po::exists("option_d") ;
bool valid = v.validate(desc);
Yea, this is a possibility.
I attach a working basic solution (many things copied from spirit ;) ), feel free to do anything you want with it. I used operator ^ for mutually exclusive options, but I'm afraid it's not perfect as it's not the same as xor!
Maybe, we can avoid defining the operators ourself and use those defined by Boost.Lambda, or Phoenix? The attached works for me. And if we store that boost::function inside options_description instance, we'll be able to call user-provided validation code after parsing is done. But not all compilers will handle this ;-) - Volodya
participants (2)
-
Stefan Slapeta
-
Vladimir Prus