
The code I posted (quoted below) for optional arguments has some problems. Getting general purpose optional argument support to work correctly appears to require modifications to the library. Just wanted to warn anybody who decided to use the posted code. Bryan Green writes:
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(DefaultProxyPor t), "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>