Reputation: 565
I'm using boost::spirit to parse text into a struct containing a fixed size array. While following the example in
and trying to use it for parsing into a struct containing a std::array (or a boost::array) i recognised that because of how BOOST_FUSION_ADAPT_STRUCT works i have to place the helper result_of::adapt_array< some_array_type >::type in the struct as well.
I think it should be possible to create a wrapper using BOOST_FUSION_ADAPT_ADT but it seems overkill just to get rid of the little adapter overhead in the struct. As i don't have many instances of it, i can live with it from a memory point of view, but it also introduces some noise.
I also think it could be possible to create an adapter which derives from the array type rather than encapsulating it to hide some of the noise but it would force me to alter all existing structs and it would leak parser overhead to the outside which is not a nice solution.
Is there something obvious I'm approaching wrong or do exist new helpers which route the overhead in the background so that they can be encapsulated in the parser?
I'm aware of Using std::array as Attribute for boost::spirit::x3 .
Here's my current code:
#include <string>
#include <array>
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
// ...code from http://www.boost.org/doc/libs/1_60_0/libs/spirit/example/qi/boost_array.cpp here
typedef result_of::adapt_array<std::array<double, 6> >::type AdaptedArrayType;
struct StructWithArray
{
StructWithArray()
: adaptedAry_(ary_)
{}
double dummy_; // see https://stackoverflow.com/questions/19823413/spirit-qi-attribute-propagation-issue-with-single-member-struct
std::array<double, 6> ary_;
AdaptedArrayType adaptedAry_;
};
BOOST_FUSION_ADAPT_STRUCT(
StructWithArray
,
(double, dummy_)
(AdaptedArrayType, adaptedAry_)
)
template <typename Iterator, typename Skipper>
struct StructWithArrayParser
: qi::grammar<Iterator, StructWithArray(), Skipper>
{
StructWithArrayParser() : StructWithArrayParser::base_type(start)
{
using qi::double_;
arrayLine %= double_ > double_ > double_ > double_ > double_ > double_;
start %= double_ > arrayLine;
}
qi::rule<Iterator, AdaptedArrayType(), Skipper> arrayLine;
qi::rule<Iterator, StructWithArray(), Skipper> start;
};
int main() {
std::string arrayStr = "0 1 2 3 4 5 6";
std::string::const_iterator it = arrayStr.begin();
std::string::const_iterator endIt = arrayStr.end();
StructWithArrayParser<std::string::const_iterator, ascii::space_type> grammar;
StructWithArray structWithArray;
bool ret = phrase_parse(it, endIt, grammar, ascii::space, structWithArray);
return 0;
}
Upvotes: 2
Views: 743
Reputation: 392911
You are going places :) You seem to have reached warp speed with Spirit in no time.
EDITED After reading the question closer I noticed that you ask for a shorter, less intrusive way.
I don't know a non-intrusive way to fix it, but you can use boost::array
if you specialize is_container
for it.
That's pretty unintrusive, but still changes your types.
#include <boost/fusion/include/tuple.hpp>
#include <boost/fusion/adapted/boost_array.hpp>
#include <boost/spirit/include/qi.hpp>
#include <string>
namespace boost { namespace spirit { namespace traits {
template <typename T, size_t N>
struct is_container<boost::array<T, N>, void> : mpl::false_ { };
} } }
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
struct StructWithArray
{
double dummy_; // see http://stackoverflow.com/questions/19823413/spirit-qi-attribute-propagation-issue-with-single-member-struct
boost::array<double, 6> ary_;
};
BOOST_FUSION_ADAPT_STRUCT(StructWithArray, dummy_, ary_)
template <typename Iterator, typename Skipper>
struct StructWithArrayParser
: qi::grammar<Iterator, StructWithArray(), Skipper>
{
StructWithArrayParser() : StructWithArrayParser::base_type(start)
{
using qi::double_;
arrayLine = double_ > double_ > double_ > double_ > double_ > double_;
start = double_ > arrayLine;
}
private:
qi::rule<Iterator, boost::array<double, 6>(), Skipper> arrayLine;
qi::rule<Iterator, StructWithArray(), Skipper> start;
};
int main() {
std::string arrayStr = "0 1 2 3 4 5 6";
using It = std::string::const_iterator;
It it = arrayStr.begin(), endIt = arrayStr.end();
StructWithArrayParser<It, ascii::space_type> grammar;
StructWithArray structWithArray;
bool ret = phrase_parse(it, endIt, grammar, ascii::space, structWithArray);
std::cout << std::boolalpha << ret << "\n";
for (double v : structWithArray.ary_)
std::cout << v << " ";
}
Prints:
true
1 2 3 4 5 6
Upvotes: 2