Pavol Droba wrote:

>> The only problem with current 'validator' is that it should validate
>> *string* and return the value. So, the example given by Tanton:
>> 
>>    _1 >= 1 && _1 <= 9)
>> 
>> would not really work --- the validator function is given a string. It's
>> probably possible to use 'notify' callback to do such kind of validation,
>> though. Or add another validator --- which is given converted value.
>> 
> 
> I see. However I think this is a little bit clumsy to use. I think it may
> be better to strip validation from the conversion.
> 
> What I had in mind is an extension to po::parameter funtion to something
> like
> 
> template< typename T >
> *unspecified* po::parameter<T>(
> string parameter_name,
> T& variable,
> const boost::function1<bool, T)& validator );
> 
> so the framework would convert string parameter to a specified type and
> then run the validator functor on the result to validate it.

I was actually thinking about splitting current "validator" into 
"interpreter", which converts string to value and validator proper. That 
should allow to write

   desc.add_options()
      ("compression", parameter<int>("n"), "compression quality").
             validator(1 < _1 && _1 <= 9)
      ;

With this feature in place, adding validator as additional argument to 
'parameter' can be considered a convenience. (Now, there are 3 ideas for
additional arguments to 'parameter', so I can't decide right now).

One problem: the above would require implementation tricks. The value 
extracted from string is stored in boost::any. Sure, you can't pass 
boost::any to the lambda function above, so some means to recover the type
stored in any would be needed. I'm not yet sure this will be all that big
problem, though.

[...]
>> > I mean something like "%02.4f" or something like that... it is just an
>> > idea. If there would be a validation predicate as an argument, regex
>> > library can be used to define regex predicate which would cover most of
>> > the cases.
>> 
>> Ah... ok. Indeed --- the validator can do that already, and in case of
>> string validation, the current code will work.
>> 
> That's nice. Can you post a piece of code as an example?

Attached is a complete example which uses regex library to validate option's 
value. The format of value is fictional, but the main idea should be clear. 
And there's example session:

    bash-2.05b$ bin/gcc/debug/regex --help
    Usage: regex [options]
    Allowed options:
      --help                 : produce a help screen
      -v [ --version ]       : print the version number
      -m [ --magic ] arg     : magic value (in NNN-NNN format)
     bash-2.05b$ bin/gcc/debug/regex -m 123
     invalid value
     bash-2.05b$ bin/gcc/debug/regex -m 123-345
    The magic is "345"

I've also realized there are no examples for custom validator now, so this 
code will most likely be added to the library.

Thanks,
Volodya








#include <boost/program_options.hpp>
#include <boost/regex.hpp>

using namespace boost;
using namespace boost::program_options;

#include <iostream>
using namespace std;

/* This validator makes sure that value is of form
   XXX-XXX 
   where X are digits. It then converts the second group to a integer
   value. This has no practical meaning, meant only to show how
   regex can be used to validate values.
*/
void fancy_parameter_validator(boost::any& a, 
                               const std::vector<std::string>& values)
{
    static regex r("\\d\\d\\d-(\\d\\d\\d)");

    // Make sure no previous assignment to 'a' was made.
    validators::check_first_occurence(a);
    // Extract the first string from 'values'. If there is more than
    // one string, it's an error, and exception will be thrown.
    const string& s = validators::get_single_string(values);

    // Do regex match and convert the interesting part to 
    // int.
    smatch match;
    if (regex_match(s, match, r)) {
        a = any(lexical_cast<int>(match[1]));
    } else {
        throw validation_error("invalid value");
    }        
}


int main(int ac, const char **av)
{
    try {
        options_description desc("Allowed options");
        desc.add_options()
        ("help", "", "produce a help screen")
        ("version,v", "", "print the version number")
        ("magic,m", "arg", "magic value (in NNN-NNN format)").
             validator(fancy_parameter_validator)
        ;
        
        options_and_arguments oa = parse_command_line(ac, av, desc);
        variables_map vm;
        store(oa, vm, desc);
   
        if (oa.count("help")) {
            cout << "Usage: regex [options]\n";
            cout << desc;
            return 0;
        }
        if (oa.count("version")) {
            cout << "Version 1.\n";
            return 0;
        }
        if (oa.count("magic")) {
            cout << "The magic is \"" << vm["magic"].as<int>() << "\"\n";
        }
    }
    catch(exception& e)
    {
        cout << e.what() << "\n";
    }    
}
_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Reply via email to