Storing the result of a repeat statement into a std::vector leads to compile error:
/usr/include/boost/spirit/home/qi/detail/pass_container.hpp:172:12: error: ambiguous
class template instantiation for ‘struct boost::spirit::qi::detail::pass_through_container_base<std::vector<Vertex3d<float> >, Vertex3d<float>, Vertex3d<float>, mpl_::bool_<false>, void>’
/usr/include/boost/spirit/home/qi/detail/pass_container.hpp:103:12: error: candidates are: struct boost::spirit::qi::detail::pass_through_container_base<Container, ValueType, Attribute, Sequence, typename boost::enable_if<boost::fusion::traits::is_sequence<Attribute> >::type>
struct pass_through_container_base<Container, ValueType, Attribute
^
/usr/include/boost/spirit/home/qi/detail/pass_container.hpp:136:12: error: struct boost::spirit::qi::detail::pass_through_container_base<Container, ValueType, Attribute, Sequence, typename boost::enable_if<boost::spirit::traits::is_container<T2> >::type>
struct pass_through_container_base<
^
/usr/include/boost/spirit/home/qi/detail/pass_container.hpp:172:12: error: invalid use of incomplete type ‘struct boost::spirit::qi::detail::pass_through_container_base<std::vector<wc3lib::Vertex3d<float> >, wc3lib::Vertex3d<float>, wc3lib::Vertex3d<float>, mpl_::bool_<false>, void>’
struct pass_through_container
^
/usr/include/boost/spirit/home/qi/detail/pass_container.hpp:50:12: error: declaration of ‘struct boost::spirit::qi::detail::pass_through_container_base<std::vector<wc3lib::Vertex3d<float> >, wc3lib::Vertex3d<float>, wc3lib::Vertex3d<float>, mpl_::bool_<false>, void>’
struct pass_through_container_base
The following code is used for the grammar:
qi::rule<Iterator, long32(), Skipper> integer_literal;
qi::rule<Iterator, float32(), Skipper> real_literal;
qi::rule<Iterator, VertexReal3d(), Skipper> vertex_real_3d;
qi::rule<Iterator, Geoset::Vertices(), Skipper, qi::locals<long32> > vertices;
integer_literal %=
lexeme[
qi::int_parser<long32>()
]
;
real_literal %=
lexeme[
qi::real_parser<float32>()
]
;
vertex_real_3d =
lit('{')
>> real_literal[at_c<0>(_val) = _1]
>> lit(',')
>> real_literal[at_c<1>(_val) = _1]
>> lit(',')
>> real_literal[at_c<2>(_val) = _1]
>> lit('}')
;
vertices =
lit("Vertices")
>> integer_literal[_a = _1]
>> lit('{')
>> repeat(_a)[
vertex_real_3d
>> lit(',')
][_val = _1] // Does not work?
>> lit('}')
;
...
typedef Vertex3d<float32> VertexData;
typedef VertexData VertexReal3d;
typedef std::vector<VertexData> Vertices;
...
BOOST_FUSION_ADAPT_ADT(
wc3lib::mdlx::VertexData,
(wc3lib::float32, wc3lib::float32, obj[0], obj[0] = val)
(wc3lib::float32, wc3lib::float32, obj[1], obj[1] = val)
(wc3lib::float32, wc3lib::float32, obj[2], obj[2] = val)
)
...
template<typename T, typename std::size_t N>
class BasicVertex : public std::array<T, N>
{
public:
typedef std::array<T, N> Base;
BasicVertex() : Base()
{
}
BasicVertex(const BasicVertex<T, N> &other) : Base(other) {
}
};
template<typename T = float32>
class Vertex3d : public BasicVertex<T, 3>
{
public:
typedef BasicVertex<T, 3> Base;
Vertex3d() : Base()
{
}
Vertex3d(T x, T y, T z)
{
(*this)[0] = x;
(*this)[1] = y;
(*this)[2] = z;
}
Vertex3d(const Base &other) : Base(other) {
}
};
The rule vertices should return a std::vector of VertexData. Therefore repeat is used to parse a fixed amount of vertices. The amount is placed as an integer value in the parsed file before the list and stored in _a.
The compile error hints that it cannot differ between "is_sequence" and "is_container". I am not an expert of Spirit, so I cannot answer what it does mean exactly.
Ok, with the edits, the question became viable.
Indeed with a (public) base class of std::array<>
and Fusion adaptation at the same time (luckily¹!) Spirit cannot decide which of the attribute assignment paths is to be taken.
So fix it either by
telling Spirit "These are not the droids you're looking for" (when it thinks for a moment that it's seeing a container):
namespace boost { namespace spirit { namespace traits {
template <>
struct is_container<wc3lib::mdlx::VertexData> : mpl::false_
{ };
} } }
not (publicly) deriving from std::array
I think you may want to ask yourself what the point is of inheriting from std::array<>
in the first place. And the way your Vertex types are defined now explicitly makes them non-POD, which means that performance is going to suffer.
Consider just
template <typename T, typename std::size_t N> class BasicVertex : public std::array<T,N> {
public:
typedef std::array<T, N> Base;
};
template <typename T = float> class Vertex3d : public BasicVertex<T, 3> {
public:
typedef BasicVertex<T, 3> Base;
};
or
template <typename T, typename std::size_t N> class BasicVertex {
public:
std::array<T, N> data_;
};
template <typename T = float> class Vertex3d : public BasicVertex<T, 3> {
};
for some performance. In reality, I'd probably write
template <typename T = float> struct Vertex3d {
T x, y, z;
};
¹ believe me, you want a library to diagnose this kind of situation