In the example (regex.cpp), the author of the library created a custom struct (magic_number) and a validate function for this struct to show how custom struct can be integrated into program options. I followed his example to create a validate function for a custom class (MyClass). Compiler complains that a lexical_cast is not available for MyClass. I then implemented std::istream& operator>>(std::istream& in, MyClass& d)
, removed void validate(.., MyClass*, ..)
, the code compiles. Can anyone explain why the example doesn't require operator>>
, while mine doesn't require validate
?
EDIT:
#include <MyLib/MyClass.h>
std::istream& operator>>(std::istream& in, MyClass& obj) {
// some code to populate obj
return in;
}
po::variables_map parseCommandLine(int argc, char* argv[]) {
po::options_description options("Options");
options.add_options()
("help", "produce help message")
("obj", po::value<MyClass>(), "")
;
po::variables_map vm;
store(po::command_line_parser(argc, argv)
.options(options).run(), vm);
notify(vm);
return vm;
}
int main(int argc, char* argv[]) {
try {
po::variables_map vm = parseCommandLine(argc, argv);
MyClass obj = vm["my"].as<MyClass>();
cout << obj << endl;
} catch(std::exception& e) {
cout << e.what() << "\n";
return 1;
}
return 0;
}
I also tried making minimum change to regex.cpp:
#include <MyLib/MyClass.h>
EDIT: add validate
. None of them solved the compiler error.
void validate(boost::any& v,
const std::vector<std::string>& values,
std::vector<MyClass>*, int)
{
}
void validate(boost::any& v,
const std::vector<std::string>& values,
MyClass*, long)
{
}
void validate(boost::any& v,
const std::vector<std::string>& values,
MyClass*, int)
{
}
EDIT: It may relate to namespaces.
After I surrounded the validate function by namespace boost { namespace program_options { }}
, the code compiled without overloading op>>. It also works if validate is put into the same namespace as MyClass. Can anyone explain this?
The basic problem you are facing is that C++ doesn't offer any facility to convent a string to an arbitrary user object (I mean without writing any code).
To solve the problem, program_options offers two possibilities:
operator>>
, which is the standard C++ way of doing so, but which may have impact in some other areas (i.e. you may want to parse your object in a specific way except on the command line). Internally, boost::lexical_cast
is used to implement the conversion and will throw an error if op>>
is not found.validate
function, which is specific to program_options but that has no impact outside option management.I guess it uses template meta programming to find out whether you have provided validate
or it will default to lexical_cast
.
I can't help you why your attempt with validate
failed since you didn't provide the code for it.
Here is a working example, though:
#include <boost/program_options.hpp>
#include <vector>
#include <string>
namespace po = boost::program_options;
namespace lib {
class MyClass
{
public:
int a;
};
void validate(boost::any& v,
const std::vector<std::string>& values,
MyClass*, int)
{
po::validators::check_first_occurrence(v);
const string& s = po::validators::get_single_string(values);
v = boost::any(MyClass { boost::lexical_cast<int>(s) } );
}
}
po::variables_map parseCommandLine(int argc, char* argv[])
{
po::options_description options("Options");
options.add_options()
("help", "produce help message")
("obj", po::value<lib::MyClass>(), "")
;
po::variables_map vm;
store(po::command_line_parser(argc, argv)
.options(options).run(), vm);
notify(vm);
return vm;
}
int main(int argc, char* argv[])
{
try {
po::variables_map vm = parseCommandLine(argc, argv);
lib::MyClass obj = vm["obj"].as<lib::MyClass>();
cout << obj.a << endl;
} catch(std::exception& e) {
cout << e.what() << "\n";
return 1;
}
return 0;
}
With a namespace, both the class and validate must belong to the same namespace.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With