Consider this code using Boost Spirit X3 (conceptually same goes for Boost Spirit Qi):
string command;
string value;
x3::parse(command.begin(), command.end(), "float:" >> x3::double_, value);
Why is this code not generating any error during compilation? Shouldn't "float:" >> x3::double_
parser have attribute of type double
and therefore not accept std::string
as 4th argument to parse
?
BTW, I know I could do this:
string value;
auto assign = [](auto& ctx){value = _attr(ctx)};
x3::parse(command.begin(), command.end(), "float:" >> x3::double_[assign], value)
which would generate an error, but it is more complicated than necessary.
As a last resort: any there any well-known replacements for sscanf
that would be type safe (possibly in boost)?
It's because automatic attribute propagation into a container is very flexible.
And std::string
is a container.
Perhaps if we do the following experiment it makes a bit more sense:
#include <boost/spirit/home/x3.hpp>
#include <iostream>
namespace x3 = boost::spirit::x3;
int main() {
//std::string command = "f: hello world";
std::string command = "f: 104 101 108 108 111 32 119 111 114 108 100";
std::string value;
x3::phrase_parse(
command.begin(),
command.end(),
"f:" >> *x3::double_, x3::blank,
value);
std::cout << value << "\n";
}
As you might surmise, it prints:
hello world
For strings this seems surprising. It would be much less of a surprise if the target was std::vector<float>
- but it would require precisely the same amount of conversions.
It's fair for each element to enjoy propagation conversions. What if you were parsing Ast nodes like:
struct Operation {
Operator op;
std::vector<Expression> operands;
}
You would hate if operands didn't implicitly convert into Expression
from Unary
, FunctionCall
, StringLiteral
etc.