
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