
Hello, recently I was faced with a situation of writing a custom validator for a certain command line option I wanted to handle. The validator was supposed to check whether the value on the command line was in a certain range. After some head scratching, I realized there's no elegant way to do this with the current validation overload function. In the end I just ended up doing the validation after the options had been parsed. I was thinking about a good way to support this, and I thought that maybe the best way is to add an additional value semantic so that the validate function could instead be: template<class T, class validation_data> void validate(boost::any& v, const std::vector<std::string>& values, const validation_data& data, T* target_type, int); and we could write add_options() ("test", value<int>()->validate(boost::interval<int>(1, 10)) ); this would require the user to provide the following overload: void validate(boost::any& v, std::vector<std::string>& values, const boost::interval<int>& data, int* target_type, int); the default implementation of validate would all use some dummy type for validation_data, this way compilation would fail if user calls validate but does not provide the appropriate overload. And if the user does not want to provide additional validation data he can simply use the current syntax, but instead would provide the following validate() overload void validate(boost::any& v, const std::vector<std::string>& values, const no_validation_data& data, T* target_type, int); Thoughts? Zach

Zachary Turner wrote:
Hello, recently I was faced with a situation of writing a custom validator for a certain command line option I wanted to handle. The validator was supposed to check whether the value on the command line was in a certain range. After some head scratching, I realized there's no elegant way to do this with the current validation overload function. In the end I just ended up doing the validation after the options had been parsed.
I was thinking about a good way to support this, and I thought that maybe the best way is to add an additional value semantic so that the validate function could instead be:
template<class T, class validation_data> void validate(boost::any& v, const std::vector<std::string>& values, const validation_data& data, T* target_type, int);
and we could write
add_options() ("test", value<int>()->validate(boost::interval<int>(1, 10)) );
this would require the user to provide the following overload:
void validate(boost::any& v, std::vector<std::string>& values, const boost::interval<int>& data, int* target_type, int);
Would it be a more generally useful approach to add value_semantics::validate that can take any function, and call that, in preference to the free-standing validate? Then, you'd implement is_in_range helper and use it like add_options() ("test", value<int>()->validate(is_in_range(1, 10)) ); ? That is something I wanted to do for a while, but never found the time. - Volodya

On Sat, Jul 11, 2009 at 2:21 AM, Vladimir Prus<vladimir@codesourcery.com> wrote:
Zachary Turner wrote:
Hello, recently I was faced with a situation of writing a custom validator for a certain command line option I wanted to handle. The validator was supposed to check whether the value on the command line was in a certain range. After some head scratching, I realized there's no elegant way to do this with the current validation overload function. In the end I just ended up doing the validation after the options had been parsed.
I was thinking about a good way to support this, and I thought that maybe the best way is to add an additional value semantic so that the validate function could instead be:
template<class T, class validation_data> void validate(boost::any& v, const std::vector<std::string>& values, const validation_data& data, T* target_type, int);
and we could write
add_options() ("test", value<int>()->validate(boost::interval<int>(1, 10)) );
this would require the user to provide the following overload:
void validate(boost::any& v, std::vector<std::string>& values, const boost::interval<int>& data, int* target_type, int);
Would it be a more generally useful approach to add value_semantics::validate that can take any function, and call that, in preference to the free-standing validate? Then, you'd implement is_in_range helper and use it like
add_options() ("test", value<int>()->validate(is_in_range(1, 10)) );
?
That is something I wanted to do for a while, but never found the time.
- Volodya
Actually I was thinking about that too and yes that would be more useful. I'm generally opposed to customization by free-standing overloads because it means you can customize only once per type, rather than per instance. So I was trying to do it with the minimum possible amount of code changes. Is there a way to implement what you suggest without breaking existing code?

Zachary Turner wrote:
add_options() ("test", value<int>()->validate(is_in_range(1, 10)) );
That is something I wanted to do for a while, but never found the time.
Actually I was thinking about that too and yes that would be more useful. I'm generally opposed to customization by free-standing overloads because it means you can customize only once per type, rather than per instance. So I was trying to do it with the minimum possible amount of code changes. Is there a way to implement what you suggest without breaking existing code?
I think it's fairly easy to write the code so that if no validate is specified on specific option, the free-standing one is called. However, if the decision is made at runtime it means that free-standing validate will be instantiated for every time, and it's a bit tricky to avoid. In theory, the 'validate' call may return a special type that knows that validate was specified. Then, operator(), if called with plain value_semantics, may instantiate free-standing validate and associate it with the option. I did not try this, so I don't know if that will be a mess. - Volodya
participants (2)
-
Vladimir Prus
-
Zachary Turner