[program_options] post-review version

The first post-review version of the program_options library is now available. I believe that all important interface changes are finished and would like to ask for feedback on the current version, before I go on. Some of the interesting changes include: - better way to describe option values - support for positional options - support for environment variables The library and documentation can be obtained at http://zigzag.cs.msu.su:7813/program_options The documentation can also be browsed online at http://zigzag.cs.msu.su:7813/program_options/html And the source can also be browsed online at http://zigzag.cs.msu.su:7813/repos/trunk/program_options Since the interface has changes quite a bit, the brief list of changes is included in docs, to help with migration. See http://zigzag.cs.msu.su:7813/program_options/html/ch01s04.html All comments are very appreciated. - Volodya

Hi Vladimir, Here are some thoughts based on reading the online docs. I did not participate in the actual review, so I could easily miss important design and implementation problems. So don't take my comments too serious :-) Section "Tutorial" ------------------------ 1. I don't like that the example hardcodes strings. 2. each line should have a comment about what it does. 3. why po::store(po::parse_command_line(ac, av, desc), vm); instead of po::variables_map vm = parse_command_line( ... ) or vm.store( ... ) ? It would make it clearer what is stored in what. 4. po::variables_map is probably a std::map, right? I think that the way to check if an argument is a bit strange, ie, if (vm.count("help")) should be if( vm.has_argument( "help" ) ) or something. 5. Why is it necessary to remember the type of compresion argument? ie, could cout << "Compression level was set to " << vm["compression"].as<int>() << ".\n"; not be written as cout << "Compression level was set to " << vm["compression"] << ".\n"; ? (if eg. a boost::variant is returned, it would just write the int) 6. Consider desc.add_options() ("help", "produce help message") why don't you have an add_options that take two and three arguments, så the first empty ones can be removed? 7. In po::value<int>(&opt)->default_value(10), I would prefer po::value<int>( opt, 10 ), 8.I don't find this too readable: po::store(po::command_line_parser(ac, av). options(desc).positional(p).run(), vm); compared to po::command_line_parser parser(ac, av); parser.set_options( desc ); parser.set_positional_options( p ); vm.store( parser.run() ); 9. Could this way of specifying composing()/default_value() be of any use option += option<int>( "xx", "xx msg" ), option_with_default<int>( ""yy", var_name, 0, "yy msg" ), option_with_compose< vector<string> >( "zz", "zz msg" ); ?. 10. This po::options_description cmdline_options; cmdline_options.add(generic).add(config).add(hidden); might be po::options_description cmdline_options; cmdline_options += generic, config, hidden; ? 11. Have you compare with the functionality of other program option libraries? I mean, it is always nice to know that this is just the best around :-) br Thorsten

Hi Thorsten,
Section "Tutorial" ------------------------
1. I don't like that the example hardcodes strings.
Could you explain?
2. each line should have a comment about what it does.
Actually, that would duplicate explanations that are already in the tutorial. Don't you think?
3. why
po::store(po::parse_command_line(ac, av, desc), vm);
instead of
po::variables_map vm = parse_command_line( ... )
Technically, this can be done by providing an operator= which takes an instance of "parsed_options". But you'd still need 'store' for the second source.
or
vm.store( ... ) ? It would make it clearer what is stored in what.
I figured out that 'store' does not need to be member, so made it non-member. There are no other reasons.
4. po::variables_map is probably a std::map, right? I think that the way to check if an argument is a bit strange, ie,
if (vm.count("help"))
should be
if( vm.has_argument( "help" ) )
or something.
The first approach is quite idiomatic, IMO. If there's enough user pressure, 'has_option' can always be added.
5. Why is it necessary to remember the type of compresion argument? ie, could
cout << "Compression level was set to " << vm["compression"].as<int>() << ".\n";
not be written as
cout << "Compression level was set to " << vm["compression"] << ".\n";
? (if eg. a boost::variant is returned, it would just write the int)
Hmm... I did not know about operator<< for boost::variant until now. But in general, you do need to know about exact type to do any processing of the value.
6. Consider
desc.add_options() ("help", "produce help message")
why don't you have an add_options that take two and three arguments, sЕ the first empty ones can be removed?
"The first empty parenthethis"? This idea did not occur to me. I think this is doable, though again, I'd like to get more opinions.
7. In
po::value<int>(&opt)->default_value(10),
I would prefer
po::value<int>( opt, 10 ),
But then po::value<int>( 10 ), comes as obvious addition, too? I think that's rather good idea.
8.I don't find this too readable:
po::store(po::command_line_parser(ac, av). options(desc).positional(p).run(), vm);
compared to
po::command_line_parser parser(ac, av); parser.set_options( desc ); parser.set_positional_options( p ); vm.store( parser.run() );
Opinions differ ;-) I prefer the first one for compactness -- in fact I'm just emulating named parameters. Maybe when we have named parameters library in Boost the syntax can change.
9. Could this way of specifying composing()/default_value() be of any use
option += option<int>( "xx", "xx msg" ), option_with_default<int>( ""yy", var_name, 0, "yy msg" ), option_with_compose< vector<string> >( "zz", "zz msg" );
?.
I think that syntantically, it requires the same number (or even larger) number of characters. Besides, what if you want to specified both default value and 'composing' flags? options_with_default_and_compose looks too long.
10. This
po::options_description cmdline_options; cmdline_options.add(generic).add(config).add(hidden);
might be
po::options_description cmdline_options; cmdline_options += generic, config, hidden;
?
Interesting! I just found some-years-old code of mine which provides support for such initialization. It worked for vectors, like: v << 1, 2, 3, 4, 5, 6; but can be easily used for +=, too. I'm just not sure this is justified here.
11.
Have you compare with the functionality of other program option libraries? I mean, it is always nice to know that this is just the best around :-)
I've looked at several other libraries during development and still have the list somewhere. Unfortunately, no comparison is present in docs. In short, most of the libraries I've seen hardcode the type of supported options. I did not seen support for several configuration sources, either. Thanks for your comments. - Volodya

Hi again,
Section "Tutorial" ------------------------
1. I don't like that the example hardcodes strings.
Could you explain? --------- writing const char* help = "help"; would enable the compiler to catch spell-errors in the constants.
2. each line should have a comment about what it does.
Actually, that would duplicate explanations that are already in the tutorial. Don't you think? ------------------ I'm in doubt :-) I do like comments because they can easily be compared to code; when you're reading block text, it can be harder to focus on where the comments apply.
9. Could this way of specifying composing()/default_value() be of any use
option += option<int>( "xx", "xx msg" ), option_with_default<int>( ""yy", var_name, 0, "yy msg" ), option_with_compose< vector<string> >( "zz", "zz msg" );
?.
I think that syntantically, it requires the same number (or even larger) number of characters. Besides, what if you want to specified both default value and 'composing' flags? options_with_default_and_compose looks too long. --------- yeah, then what about option += option<int>( ""xx"", var_name, compose_flag | other_flag ) ? That use of flags might be more idiomatic.
10. This
po::options_description cmdline_options; cmdline_options.add(generic).add(config).add(hidden);
might be
po::options_description cmdline_options; cmdline_options += generic, config, hidden;
?
Interesting! I just found some-years-old code of mine which provides support for such initialization. It worked for vectors, like: v << 1, 2, 3, 4, 5, 6; but can be easily used for +=, too. I'm just not sure this is justified here. -------------- Actually, one could choose to use my assign library if it gets accepted. You would probably only have to write one overload of operator+= so it can recognize your types. There is also another use. Let's say you make a function add(): program_options po; add( po )( "xx", df, "xx msg)(...)(...) that should work ou of the box with different tuplesizes. Making add() and operator+() is about the same amount of work, probably 3-4 four lines each. br Thorsten

Thorsten Ottosen wrote:
Could you explain? --------- writing
const char* help = "help";
would enable the compiler to catch spell-errors in the constants.
I see. I did not run into problems with hardcoded strings yet, so did not consider this important.
2. each line should have a comment about what it does.
Actually, that would duplicate explanations that are already in the tutorial. Don't you think? ------------------ I'm in doubt :-) I do like comments because they can easily be compared to code; when you're reading block text, it can be harder to focus on where the comments apply.
Ok, I'll note your opinion.
9. Could this way of specifying composing()/default_value() be of any use
option += option<int>( "xx", "xx msg" ), option_with_default<int>( ""yy", var_name, 0, "yy msg" ), option_with_compose< vector<string> >( "zz", "zz msg" );
?.
I think that syntantically, it requires the same number (or even larger) number of characters. Besides, what if you want to specified both default value and 'composing' flags? options_with_default_and_compose looks too long. ---------
yeah, then what about
option += option<int>( ""xx"", var_name, compose_flag | other_flag )
? That use of flags might be more idiomatic.
The problem here is different: some modifiers, like "default_value" and "notifier" have a parameter, so they can't be just bitwise-ored. So, even if "compose_flag" can be used as you suggest, there will be two syntaxes from specifying modifiers: option<int>( ""xx"", var_name, compose_flag | other_flag ). notifier(print_values) and I'd prefer just one syntax -- for consistency.
10. This
po::options_description cmdline_options; cmdline_options.add(generic).add(config).add(hidden);
might be
po::options_description cmdline_options; cmdline_options += generic, config, hidden;
?
Interesting! I just found some-years-old code of mine which provides support for such initialization. It worked for vectors, like:
v << 1, 2, 3, 4, 5, 6;
but can be easily used for +=, too. I'm just not sure this is justified here. --------------
Actually, one could choose to use my assign library if it gets accepted.
I did not know about it. I think I'll take a look
You would probably only have to write one overload of operator+= so it can recognize your types. There is also another use. Let's say you make a function add():
program_options po;
add( po )( "xx", df, "xx msg)(...)(...)
that should work ou of the box with different tuplesizes. Making add() and operator+() is about the same amount of work, probably 3-4 four lines each.
That's handy! - Volodya

Vladimir Prus <ghost@cs.msu.su> writes:
2. each line should have a comment about what it does.
Actually, that would duplicate explanations that are already in the tutorial. Don't you think?
In this case some duplication could be helpful. -- Dave Abrahams Boost Consulting www.boost-consulting.com

Why not a default validator? namespace po = boost::program_options; namespace boost { namespace program_options { template<typename T> void validator<T>::operator()(any& v, const vector<string>& xs) { validators::check_first_occurence(v); string s(validators::get_single_string(xs)); try { v = any(lexical_cast<T>(s)); } catch(const bad_lexical_cast&) { throw validation_error("'" + s + "' doesn't look like a double value."); } } }} This solves my immediate problem, which is that (strangely) program_options has a validator for float but not for double.

Neal D. Becker wrote:
Why not a default validator? namespace po = boost::program_options;
namespace boost { namespace program_options { template<typename T> void validator<T>::operator()(any& v, const vector<string>& xs) { } }}
This solves my immediate problem, which is that (strangely) program_options has a validator for float but not for double.
I think it is addressed. You would just use value<double>() and it should work. The previous version had explicit instantiation for some types, but it no longer the case. - Volodya

Vladimir Prus wrote:
Neal D. Becker wrote:
Why not a default validator? namespace po = boost::program_options;
namespace boost { namespace program_options { template<typename T> void validator<T>::operator()(any& v, const vector<string>& xs) { } }}
This solves my immediate problem, which is that (strangely) program_options has a validator for float but not for double.
I think it is addressed. You would just use
value<double>()
and it should work. The previous version had explicit instantiation for some types, but it no longer the case.
Doesn't work for me: Here is test program: #include <boost/program_options.hpp> #include <iostream> using namespace std; namespace po = boost::program_options; // namespace boost { namespace program_options { // template<typename T> // void validator<T>::operator()(any& v, const vector<string>& xs) // { // validators::check_first_occurence(v); // string s(validators::get_single_string(xs)); // try { // v = any(lexical_cast<T>(s)); // } // catch(const bad_lexical_cast&) { // throw validation_error("'" + s + "' doesn't look like right"); // } // } // }} int main (int argc, char** argv) { try { po::options_description desc("Allowed options"); desc.add_options() ("help", "produce help message") ("compression", po::value<int>(), "set compression level") ("stupidity", po::value<double>(), "set stupidity level") ; po::variables_map vm; po::store(po::parse_command_line(argc, argv, desc), vm); po::notify(vm); if (vm.count("help")) { cout << desc << "\n"; return 1; } if (vm.count("compression")) { cout << "Compression level was set to " << vm["compression"].as<int>() << ".\n"; } else { cout << "Compression level was not set.\n"; } if (vm.count("stupidity")) { cout << "Stupidity level was set to " << vm["stupidity"].as<double>() << ".\n"; } else { cout << "Stupidity level was not set.\n"; } } catch (exception& e) { cerr << "error: " << e.what() << '\n'; } } Result: make g++ -g -I /usr/local/src/boost_1_31_0 -o Test1 Test1.cc -L /usr/local/src/boost_1_31_0/stage/lib -l boost_program_options-gcc /tmp/cceRudK0.o(.gnu.linkonce.t._ZNK5boost15program_options11typed_valueIdE5parseERNS_3anyERKSt6vectorISsSaISsEE+0x14): In function `boost::program_options::typed_value<double>::parse(boost::any&, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&) const': /usr/local/src/boost_1_31_0/boost/detail/shared_count.hpp:145: undefined reference to `boost::program_options::validator<double>::operator( (boost::any&, std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&)' collect2: ld returned 1 exit status make: *** [Test1] Error 1 Uncomment the validator and it works.

Neal D. Becker wrote:
Doesn't work for me:
Result: undefined reference to `boost::program_options::validator<double>::operator(
Well, I'm sure I wanted to remove specialization, but the code proves I did not. Ok, this time I really fixed it. The fix will be included in the next version, and those with Subversion client can directly get it from http://zigzag.cs.msu.su:7813/repos/trunk/program_options Thanks, Volodya

Well, I'm sure I wanted to remove specialization, but the code proves I did not. Ok, this time I really fixed it. The fix will be included in the next version, and those with Subversion client can directly get it from
Unfortunately, now linker claims there isn't validator for std::string (try custom_syntax example) Regards, Janusz

Janusz Piwowarski wrote:
Well, I'm sure I wanted to remove specialization, but the code proves I did not. Ok, this time I really fixed it. The fix will be included in the next version, and those with Subversion client can directly get it from
Unfortunately, now linker claims there isn't validator for std::string (try custom_syntax example)
Strange. It works for me. Additionally, value_semantic.cpp contains the following: template<> void validator<string>::operator()(any& v, const vector<string>& xs) { .... } Could you take a look if your 'build/Jamfile' mention that file? - Volodya

template<> void validator<string>::operator()(any& v, const vector<string>& xs) { .... }
Could you take a look if your 'build/Jamfile' mention that file? Yes, it mention it. Linker message:
..\..\..\bin\boost\libs\program_options\example\custom_syntax.exe\mingw\debu g\custom_syntax.obj(.text$_ZNK5boost15program_options11typed_valueISsE5parse ERNS_3anyERKSt6vectorISsSaISsEE+0x14): In function `Z7reg_fooRKSs': D:/sources/boost/libs/program_options/example/../../../libs/program_options/ example/custom_syntax.cpp:22: undefined reference to `boost::program_options::validator<std::string>::operator()(boost::any&, std::vector<std::string, std::allocator<std::string> > const&)' I'm using mingw with gcc v 3.2.3 Janusz

Janusz Piwowarski wrote:
template<> void validator<string>::operator()(any& v, const vector<string>& xs) { .... }
Could you take a look if your 'build/Jamfile' mention that file? Yes, it mention it. Linker message:
..\..\. \bin\boost\libs\program_options\example\custom_syntax.exe\mingw\debu
g\custom_syntax.obj(.text$_ZNK5boost15program_options11typed_valueISsE5parse
ERNS_3anyERKSt6vectorISsSaISsEE+0x14): In function `Z7reg_fooRKSs':
D:/sources/boost/libs/program_options/example/../../../libs/program_options/
example/custom_syntax.cpp:22: undefined reference to `boost::program_options::validator<std::string>::operator()(boost::any&, std::vector<std::string, std::allocator<std::string> > const&)'
Ok, more ideas: 1. Could you remove all bin directories and rebuild? Maybe, somehow, library was not updated. 2. I presume you're using Boost.Build V1? Maybe, you can get preprocessed version of custom_syntax.cpp with bjam -n -sBUILD="gcc <cxxflags>-save-temps" and see if specialization for std::string is declared. Maybe, some other header is used. 3. Does mingw has a tool to look at content of library/object file? On linux, readelf might be used. If yes, it should be possible to look at content of value_semantic.obj, the library and the referring file to figure if necessary definition is provided. If there's no such tool, or you never used it, you can send me the files (off-list, to reduce traffic), and I'll take a look. - Volodya

Hello Volodya The sample starts to link after remove specialization declaration from value_semantic.tcc file (lines 74-76 in latest(257) svn revision). Regards, Janusz

Hi Janusz,
The sample starts to link after remove specialization declaration from value_semantic.tcc file (lines 74-76 in latest(257) svn revision).
Strange. IIRC, according the the standard, defining explicit specialization in .cpp without first declaring it in header it not allows. Specifically, std::14.7.3/6 says that explicit specialization should be declared before first use. Could it be a bug in mingw? Their site tells 3.3 is available, maybe you can try it? - Volodya

Hi Janusz,
Could it be a bug in mingw? Their site tells 3.3 is available, maybe you can try it?
With gcc 3.3.1 works fine.
Good.
BTW, in value_semantic.tcc file members of namespace validators are doubly declared. It's intentional?
Nope, that's some leftover. Removed in revision 260. Thanks, Volodya

Hi Janusz, Janusz Piwowarski wrote:
The sample starts to link after remove specialization declaration from value_semantic.tcc file (lines 74-76 in latest(257) svn revision).
Ok, I've reproduced this problem with g++ 3.2 -- seems like problem specific to that version. Workaround comitted in revision 259 -- I don't declare specialization for 3.2. Thanks, Volodya

"Janusz Piwowarski" <jpiw@go2.pl> writes:
Hello Volodya
The sample starts to link after remove specialization declaration from value_semantic.tcc file (lines 74-76 in latest(257) svn revision).
The boost convention of ending all C++ files with .*pp is _extremely_ useful. I hope when this stuff is checked in we can avoid introducing new conventions. -- Dave Abrahams Boost Consulting www.boost-consulting.com

At 05:59 PM 3/22/2004, David Abrahams wrote:
"Janusz Piwowarski" <jpiw@go2.pl> writes:
Hello Volodya
The sample starts to link after remove specialization declaration from value_semantic.tcc file (lines 74-76 in latest(257) svn revision).
The boost convention of ending all C++ files with .*pp is _extremely_ useful. I hope when this stuff is checked in we can avoid introducing new conventions.
I second that. Every new file extension requires changes to automated tools like the inspection program, too. --Beman

Beman Dawes wrote:
The boost convention of ending all C++ files with .*pp is _extremely_ useful. I hope when this stuff is checked in we can avoid introducing new conventions.
I second that.
Every new file extension requires changes to automated tools like the inspection program, too.
I buy this argument. The '*.tcc' convention comes from the times when I was using borland -- the standard library there used *.tcc extension for template bodies. I'll rename the files somehow. - Volodya

Now bjam chokes: bjam -sTOOLS=gcc stage --------------------------------------------------------------------- skipping Boost.Python library build due to missing or incorrect configuration couldn't find Python.h in "/usr/local/include/python2.2" You can configure the location of your python installation by setting: PYTHON_ROOT - currently "/usr/local" PYTHON_VERSION - The 2-part python Major.Minor version number (e.g. "2.2", NOT "2.2.1") - currently "2.2" The following are automatically configured from PYTHON_ROOT if not otherwise set: PYTHON_LIB_PATH - path to Python library object; currently "/usr/local/lib/python2.2/config" PYTHON_INCLUDES - path to Python #include directories; currently "/usr/local/include/python2.2" --------------------------------------------------------------------- /usr/local/src/boost_1_31_0/libs/program_options/build/Jamfile:3: in load-jamfiles *** argument error * rule project ( name : location ? ) * called with: ( boost/program_options : source-location ../src ) * extra argument ../src /usr/local/src/boost_1_31_0/tools/build/v1/allyourbase.jam:1229:see definition of rule 'project' being called /usr/local/src/boost_1_31_0/tools/build/v1/boost-base.jam:1511: in dependent-include /usr/local/src/boost_1_31_0/tools/build/v1/boost-base.jam:2773: in install-subinclude Jamfile:118: in load-jamfiles /usr/local/src/boost_1_31_0/tools/build/v1/bootstrap.jam:15: in boost-build /usr/local/src/boost_1_31_0/boost-build.jam:16: in module scope

Neal D. Becker wrote:
Now bjam chokes: /usr/local/src/boost_1_31_0/libs/program_options/build/Jamfile:3: in load-jamfiles *** argument error * rule project ( name : location ? )
Ah.. the problem is that files called "Jamfile" are actually for Boost.Build V2. I've done the necessary renames to make both Boost.Build version happy. Please update and try again. Thanks, Volodya

Hello Volodya I try to use program_options for single config file, with options_description where all options are mapped to variables ( value<T>(&variable)->default_value(x) ). For now, i must use extra variable_map, it's possible to omit it? And, second question, do you think about interface to create own validators? Regards, Janusz

Hi Janusz,
I try to use program_options for single config file, with options_description where all options are mapped to variables ( value<T>(&variable)->default_value(x) ). For now, i must use extra variable_map, it's possible to omit it?
No -- I meant variables_map to be the primary interface. However, I think that in your case, the only drawback is extra lines in the code. Or there's something else?
And, second question, do you think about interface to create own validators?
This depends on your definition of validator. Is that's a function to check that the value is withing valid range, or something like that, you can use 'notifier'. If you want to customize the parsing, the current way is: 1. Declare some class derived from typed_value<YourType> and override the 'parse' method. 2. Specialize the 'value' function to return instance of your type. HTH, Volodya

I try to use program_options for single config file, with options_description where all options are mapped to variables ( value<T>(&variable)->default_value(x) ). For now, i must use extra variable_map, it's possible to omit it?
No -- I meant variables_map to be the primary interface. However, I think
Hello that
in your case, the only drawback is extra lines in the code. Or there's something else?
You're right.
And, second question, do you think about interface to create own validators? [...] If you want to customize the parsing, the current way is:
1. Declare some class derived from typed_value<YourType> and override the 'parse' method.
2. Specialize the 'value' function to return instance of your type.
It's it, thanks. Janusz

Janusz Piwowarski wrote:
And, second question, do you think about interface to create own validators? [...] If you want to customize the parsing, the current way is:
1. Declare some class derived from typed_value<YourType> and override the 'parse' method.
2. Specialize the 'value' function to return instance of your type.
It's it, thanks.
In fact, I've given you the most powerfull method, which can be used to override everything. For changing the parsing behaviour, specializing 'validator' might be easier. - Volodya

Vladimir Prus wrote:
The first post-review version of the program_options library is now available. I believe that all important interface changes are finished and would like to ask for feedback on the current version, before I go on.
Some of the interesting changes include:
- better way to describe option values - support for positional options - support for environment variables
The library and documentation can be obtained at
http://zigzag.cs.msu.su:7813/program_options
The documentation can also be browsed online at
http://zigzag.cs.msu.su:7813/program_options/html
And the source can also be browsed online at
http://zigzag.cs.msu.su:7813/repos/trunk/program_options
Since the interface has changes quite a bit, the brief list of changes is included in docs, to help with migration. See
http://zigzag.cs.msu.su:7813/program_options/html/ch01s04.html
All comments are very appreciated.
Is there something like a package version, which may be used to decide, which program_options library version actually is used? This would be very important, because there were some interface breaking changes and existing code, which relies on the po lib has to be adjusted accordingly. Regards Hartmut

Vladimir Prus wrote:
The first post-review version of the program_options library is now available. I believe that all important interface changes are finished and would like to ask for feedback on the current version, before I go on.
Some of the interesting changes include:
- better way to describe option values - support for positional options - support for environment variables
The library and documentation can be obtained at
http://zigzag.cs.msu.su:7813/program_options
The documentation can also be browsed online at
http://zigzag.cs.msu.su:7813/program_options/html
And the source can also be browsed online at
http://zigzag.cs.msu.su:7813/repos/trunk/program_options
Since the interface has changes quite a bit, the brief list of changes is included in docs, to help with migration. See
http://zigzag.cs.msu.su:7813/program_options/html/ch01s04.html
All comments are very appreciated.
In addition to the mentioned interface changes I've stumbled over the following issues/incompatibilities with the reviewed version: 1. the parse_command_line() function taking a vector<> of the arguments doesn't exist anymore. Is it possible to re-add it? This seems to be as easy as adding: parsers.hpp(102): /** Creates instance of 'command_line_parser', passes a vector containing the arguments to it, and returns the result of calling the 'run' method. */ parsed_options parse_command_line(std::vector<std::string> &args, const options_description& desc, int style = 0, function1<std::pair<std::string, std::string>, const std::string&> ext = ext_parser()); parsers.cpp(180): parsed_options parse_command_line(std::vector<std::string> &args, const options_description& desc, int style, function1<std::pair<string, string>, const string&> ext) { return command_line_parser(args).options(desc).style(style). extra_parser(ext).run(); } 2. The examples doesn't seem to be updated to the new po interface (at least the real.cpp and regex.cpp examples) 3. As I've already pointed out, it is very important (at least for me, but I assume for others using older versions of the library too) to have some means of getting the version of the po library. I suggest adding: #define BOOST_PROGRAM_OPTIONS_VERSION 0x0200 to the program_options.hpp file, or to a separate file, which is included by all the other po headers. 4. Now, that the options_and_arguments class has gone, is there a means of getting access to the arguments given on a command line (I mean all the remaining stuff, which isn't recognized as a valid option/parameter)? I can't find any documentation on this topic and wasn't able to find anything related browing through the sources. 5. In the file overview.xml in the code box under the Storage component heading the argument sequence for the store() function doesn't match the corresponding documentation/code. 6. I find it very hmmm distracting, that the syntax of the add_options() construct has changed significantly! Isn't there any way to make it more compatible with the syntax used in the reviewed version? The only way I see now is to include two versions of the add_options() code into my application (Wave), which is very ugly! Or, I have to abandon the support for the 'older' syntax, but this puts additional burden onto the users of Wave, because they will have to keep track of the version of the po library to use. I would very much like to keep Wave compatible with the pre-released version of the po library too! Certainly, this issue seems to be important until the next Boost release only, but this may take some time and even then I would like to support the usage of Boost at least beginning with the V1.30.2. 7. What's the equivalent for the parameter and validator classes, which were contained in the reviewed version? Regards Hartmut

Hi Hartmut,
Since the interface has changes quite a bit, the brief list of changes is included in docs, to help with migration. See
http://zigzag.cs.msu.su:7813/program_options/html/ch01s04.html
All comments are very appreciated.
In addition to the mentioned interface changes I've stumbled over the following issues/incompatibilities with the reviewed version:
1. the parse_command_line() function taking a vector<> of the arguments doesn't exist anymore. Is it possible to re-add it? This seems to be as easy as adding:
The problem is that the number of overloads of 'parse_command_line' was too high. What about using vector<string> v; command_line_parser(v).options(desc).run() ? This syntax essentially emulated named function parameters and avoid the need to have large number of overloads.
2. The examples doesn't seem to be updated to the new po interface (at least the real.cpp and regex.cpp examples)
Yes, 'real.cpp' and 'regex.cpp' are out-of-date, that's why they are not built by Jamfile. I'll try to do something about it.
3. As I've already pointed out, it is very important (at least for me, but I assume for others using older versions of the library too) to have some means of getting the version of the po library. I suggest adding:
#define BOOST_PROGRAM_OPTIONS_VERSION 0x0200
to the program_options.hpp file, or to a separate file, which is included by all the other po headers.
This is possible, but let's discuss how to deal with interface changes, see below.
4. Now, that the options_and_arguments class has gone, is there a means of getting access to the arguments given on a command line (I mean all the remaining stuff, which isn't recognized as a valid option/parameter)? I can't find any documentation on this topic and wasn't able to find anything related browing through the sources.
Yes. 1. Use 'positional_options_descriptions' to handle positional options too. 2. The 'parsed_options' class returned by the parser has a vector of 'option' instance. An option which has 'position_key' not equal to -1 is positional option. So can run remove_copy_if to get positional options
5. In the file overview.xml in the code box under the Storage component heading the argument sequence for the store() function doesn't match the corresponding documentation/code.
Fixed, thanks!
6. I find it very hmmm distracting, that the syntax of the add_options() construct has changed significantly! Isn't there any way to make it more compatible with the syntax used in the reviewed version?
I'm afraid it's hard. The major reason for change is that the revieved syntax was somewhat string-oriented. For example, default values were specified as strings, and in general, the information about real type was so deeply hidden, than only the 'parameter' function knew the type.
The only way I see now is to include two versions of the add_options() code into my application (Wave), which is very ugly! Or, I have to abandon the support for the 'older' syntax, but this puts additional burden onto the users of Wave, because they will have to keep track of the version of the po library to use. I would very much like to keep Wave compatible with the pre-released version of the po library too! Certainly, this issue seems to be important until the next Boost release only, but this may take some time and even then I would like to support the usage of Boost at least beginning with the V1.30.2.
That's a question. I meant that it would work like this: 1. I retain the prereview version on my site and on sf.net. 2. When you have the time you upgrade the syntax to the new one and notify me 3. I remove the old version. At this moment, users would have to obtains the new version of program_options. It's possible to use BOOST_PROGRAM_OPTIONS_VERSION and #error to produce nice message "Please get new program_options library" rather then a number of compilation failures. This means some work for users, but it's one-time. On the contrary, supporting two syntaxes at the same time might be really hard.
7. What's the equivalent for the parameter and validator classes, which were contained in the reviewed version?
By validator, you mean the way you handle 'include_paths' class in Wave? The syntax you've used is gone, but you can achieve the same effect with specialization of the 'validator' class: template<> void validator<include_paths>::operator(.....) { ... } The argument and the body should be the same as for include_path::validate. Or you could just forward to that member function. As for 'parameter' -- it was function in the revieved version. It's now called 'value' and does not take the "name" argument. - Volodya

Vladimir Prus wrote:
1. the parse_command_line() function taking a vector<> of the arguments doesn't exist anymore. Is it possible to re-add it? This seems to be as easy as adding:
The problem is that the number of overloads of 'parse_command_line' was too high. What about using
vector<string> v; command_line_parser(v).options(desc).run()
? This syntax essentially emulated named function parameters and avoid the need to have large number of overloads.
Ok, this works. But isn't it better to add this single parse_command_line overload anyway? IMHO the vector<> based version is of major interest. If not, your solution should be added to a How to? Section inside the docs.
2. The examples doesn't seem to be updated to the new po interface (at least the real.cpp and regex.cpp examples)
Yes, 'real.cpp' and 'regex.cpp' are out-of-date, that's why they are not built by Jamfile. I'll try to do something about it.
Ok, that's fine. I would like to see more examples though.
1. Use 'positional_options_descriptions' to handle positional options too. 2. The 'parsed_options' class returned by the parser has a vector of 'option' instance. An option which has 'position_key' not equal to -1 is positional option. So can run remove_copy_if to get positional options
This should be added to a How to? section of the documentation too.
to use. I would very much like to keep Wave compatible with the pre-released version of the po library too! Certainly, this issue seems to be important until the next Boost release only, but this may take some time and even then I would like to support the usage of Boost at least beginning with the V1.30.2.
That's a question. I meant that it would work like this: 1. I retain the prereview version on my site and on sf.net. 2. When you have the time you upgrade the syntax to the new one and notify me 3. I remove the old version. At this moment, users would have to obtains the new version of program_options. It's possible to use BOOST_PROGRAM_OPTIONS_VERSION and #error to produce nice message "Please get new program_options library" rather then a number of compilation failures.
This means some work for users, but it's one-time. On the contrary, supporting two syntaxes at the same time might be really hard.
Ok, I would like to do the following. Since there are two versions of Wave out anyway (a stable version 1.0.x and the boostified development version 1.1.x, which BTW is the one submitted for Boost review), I would change only the development version to match the new interface. This would require - to add the mentioned BOOST_PROGRAM_OPTIONS_VERSION (for issuing an #error for the stable Wave) - to hold the review Boost.ProgramOptions library version for some time from now on available (at least until Wave possibly passes Boost review, after which I would release Wave 1.2.0). This could be done on your site, but it is also possible to boundle the 'old' po with the stable Wave version. Thought's?
7. What's the equivalent for the parameter and validator classes, which were contained in the reviewed version?
By validator, you mean the way you handle 'include_paths' class in Wave? The syntax you've used is gone, but you can achieve the same effect with specialization of the 'validator' class:
template<> void validator<include_paths>::operator(.....) { ... }
Again, I would like to see some more samples or additional sections in the How to? document.
The argument and the body should be the same as for include_path::validate. Or you could just forward to that member function.
As for 'parameter' -- it was function in the revieved version. It's now called 'value' and does not take the "name" argument.
Thanks for your explanations. It seems, that Wave works now with the new po version. I'll chack it in after some additional tests really soon. New questions/issues: 1. Why the new include files aren't included by the main program_options.hpp file? 2. program_options/config.hpp refers to BOOST_VERSION, shouldn't be <boost/version.hpp> included as well? Additionally I've attached some patches, which I had to apply to make the po library compile with the VC7.1 while used with Wave. Regards Hartmut
participants (7)
-
Beman Dawes
-
David Abrahams
-
hartmutkaiser@t-online.de
-
Janusz Piwowarski
-
Neal D. Becker
-
Thorsten Ottosen
-
Vladimir Prus