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 typed_value : public po::typed_value
{
public:
typed_value(T* store_to)
: po::typed_value(store_to) {}
typed_value* optional_token(const T &v)
{
m_optional_default_value = boost::any(v);
m_optional_default_value_as_text =
boost::lexical_caststd::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::name();
}
unsigned min_tokens() const
{
if (!m_optional_default_value.empty())
return 0;
else
return po::typed_value::min_tokens();
}
void xparse(boost::any& value_store,
const std::vector& 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::apply_default(value_store);
}
void notify(const boost::any& value_store) const {
if (!m_optional_default_value.empty() && value_store.empty())
po::typed_value::notify(m_optional_default_value);
else
po::typed_value::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 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(&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>