
Bryan Green writes:
Vladimir Prus writes:
I assume you mean that, for example
--foobar=10
explicitly provides a value of 'foobar', and
--foobar
Precisely.
Would it not be that, if not given, vm.count("arg") == 0; and if it was given, vm["arg"] would either be user-specified, or a default? Something like this perhaps:
desc.add_options() ("listen,l", po::value<int>()->optional_token()->default_value(5555), "listen on a port") ; ... bool do_listening = false; if (vm.count() != 0) { do_listening = true; listen_port = vm["listen"].as<int>(); }
Here is my (working) extension of program_options to support GNU-longopt-style optional arguments. It requires two components: an 'extra_parser', and an extended 'typed_value'. It would be nice to see program_options modified in such a way that the 'extra_parser' was not necessary here (something I'd be happy to attempt). I could have overridden the 'validate' function instead of extending 'typed_value', but I wanted a solution that was type-independent, and could therefore be incorporated into the program_options library. <code> namespace po_ext { template <class T, class charT = char> class typed_value : public po::typed_value<T,charT> { public: typed_value(T* store_to) : po::typed_value<T,charT>(store_to) {} typed_value* optional_token(const T &v) { m_optional_default_value = boost::any(v); m_optional_default_value_as_text = boost::lexical_cast<std::string>(v); return this; } typed_value* optional_token(const T &v, const std::string& textual) { m_optional_default_value = boost::any(v); m_optional_default_value_as_text = textual; return this; } public: // value semantic overrides std::string name() const { if (!m_optional_default_value.empty() && !m_optional_default_value_as_text.empty()) { return "[=" + m_optional_default_value_as_text + "]"; } else return po::typed_value<T,charT>::name(); } unsigned min_tokens() const { if (!m_optional_default_value.empty()) return 0; else return po::typed_value<T,charT>::min_tokens(); } void xparse(boost::any& value_store, const std::vector<std::basic_string<charT> >& new_tokens) const { if (!new_tokens.empty() || m_optional_default_value.empty()) po::validate(value_store, new_tokens, (T*)0, 0); } bool apply_default(boost::any& value_store) const { if (!m_optional_default_value.empty()) return false; else return po::typed_value<T,charT>::apply_default(value_store); } void notify(const boost::any& value_store) const { if (!m_optional_default_value.empty() && value_store.empty()) po::typed_value<T,charT>::notify(m_optional_default_value); else po::typed_value<T,charT>::notify(value_store); } private: boost::any m_optional_default_value; std::string m_optional_default_value_as_text; }; template <class T> typed_value<T>* value(T *v) { typed_value<T>* r = new typed_value<T>(v); return r; } } pair<string, string> parse_opt(const string& s) { if (s.find("--proxy=") == 0) { return make_pair(string("proxy"), s.substr(8)); } else { return make_pair(string(), string()); } } enum { DefaultProxyPort = 8869u }; int main(int argc,char *argv[]) { uint16_t proxy_port; po::options_description desc("options"); desc.add_options() ("proxy,p", po_ext::value<uint16_t>(&proxy_port)->optional_token(DefaultProxyPort), "run the proxy service") ; po::variables_map vm; try { po::store(po::command_line_parser(argc, argv).options(desc) .extra_parser(parse_opt).run(), vm); po::notify(vm); } catch (exception &e) { cout << e.what() << endl; return EXIT_FAILURE; } if (vm.count("proxy")) enable_the_proxy(proxy_port); do_your_thing(); return EXIT_SUCCESS; } </code>