This question concerns the parsing of values in a Boost::program_options
configuration file.
I have a simple custom data structure:
struct Vector {
double x, y, z;
};
I have an istream deserialiser for the format "(x, y, z)
" that I borrowed from another SO post:
// https://codereview.stackexchange.com/a/93811/186081
struct Expect {
char expected;
Expect(char expected) : expected(expected) {}
friend std::istream& operator>>(std::istream& is, Expect const& e) {
char actual;
if ((is >> actual) && (actual != e.expected)) {
is.setstate(std::ios::failbit);
}
return is;
}
};
template<typename CharT>
std::basic_istream<CharT> &
operator>>(std::basic_istream<CharT> &in, Vector &v) {
in >> Expect('(') >> v.x
>> Expect(',') >> v.y
>> Expect(',') >> v.z
>> Expect(')');
return in;
}
I am using an instance of Vector
as a value store for Boost::program_options
:
Vector vector {0.0, 0.0, 0.0};
po::options_description opts("Usage");
opts.add_options()
("vector", po::value(&vector), "The vector");
po::variables_map vm;
po::store(po::parse_config_file("config.cfg", opts, true), vm);
po::notify(vm);
The problem is that the configuration file format does not work if the vector value representation contains spaces. For example, this config file parses correctly:
vector = (0.0,1.1,2.2)
However this, with spaces, does not parse:
vector = (0.0, 1.1, 2.2)
Instead, program_options
throws:
the argument ('(0.0, 1.1, 2.2)') for option 'vector' is invalid
However, for options that are declared as std::string
, spaces seem to be OK:
some_string = this is a string
I found a few posts that mentioned using quotes, however this doesn't seem to work (same error):
vector = "(0.0, 1.1, 2.2)"
A few other posts suggest custom parsers, however I'm not sure how I'd go about implementing this, and it seems like a lot of work just to handle a few spaces.
I assume this behaviour comes from the way command-line options are parsed, even though this is config-file parsing. In this case, a command line like --vector (0.0, 1.1, 2.2)
would not make much sense (ignoring the use of shell-reserved characters (
& )
for now)
Is there a good way to handle this?