使用重复将灵气存储到 std::vector 中会导致模棱两可的类模板实例化
Boost Spirit Qi storing into std::vector using repeat leads to ambiguous class template instantiation
将重复语句的结果存储到 std::vector 中会导致编译错误:
/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
以下代码用于语法:
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) {
}
};
规则顶点应返回 VertexData 的 std::vector。因此,重复用于解析固定数量的顶点。该金额作为整数值放置在列表之前的解析文件中,并存储在_a中。
编译错误提示它在"is_sequence"和"is_container"之间不能区别。我不是圣灵的专家,所以我无法回答它到底是什么意思。
这是我使其自包含的结果。
住在科里鲁
我选择调整矢量数据类型。(我注意到为时已晚,你可能没有)。
这使得语法过于复杂。我不确定到底是什么不起作用,因为好吧,当代码编译时它确实有效......
因此,让我们在代码清理和示例引导中进行另一个练习:
- 删除了语义操作
- 删除了两条规则
- 添加了调试信息
-
删除了此处古怪的必需尾随
','
:'{' >> repeat(_a)[ vertex_real_3d >> (',' | &lit('}')) ] >> '}'
-
删除了
operator%=
的冗余使用 - 删除了
qi::lit()
的冗余用途 - 不要在语法声明中公开
qi::locals<>
(这是一个实现细节)
现在代码的时钟为 77 行(比以前少了 25 行):
住在科里鲁
//#define BOOST_SPIRIT_DEBUG
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
using long32 = int32_t;
using float32 = float;
namespace Geoset {
template <typename T>
struct Vertex3d {
T a,b,c;
};
typedef Vertex3d<float32> VertexData;
typedef VertexData VertexReal3d;
typedef std::vector<VertexData> Vertices;
}
BOOST_FUSION_ADAPT_STRUCT(Geoset::VertexData, (float32, a)(float32, b)(float32, c))
template <typename Iterator, typename Skipper = qi::space_type>
struct grammar : qi::grammar<Iterator, Geoset::Vertices(), Skipper> {
grammar() : grammar::base_type(start) {
using namespace qi;
vertex_real_3d =
'{' >> real_literal >> ','
>> real_literal >> ','
>> real_literal >> '}'
;
vertices %=
"Vertices"
>> omit [ integer_literal[_a = _1] ]
>> '{' >> repeat(_a)[ vertex_real_3d >> (',' | &lit('}')) ] >> '}'
;
start = vertices;
BOOST_SPIRIT_DEBUG_NODES((start)(vertices)(vertex_real_3d))
}
private:
qi::int_parser<long32> integer_literal;
qi::real_parser<float32> real_literal;
qi::rule<Iterator, Geoset::VertexReal3d(), Skipper> vertex_real_3d;
qi::rule<Iterator, Geoset::Vertices(), Skipper, qi::locals<long32> > vertices;
qi::rule<Iterator, Geoset::Vertices(), Skipper> start;
};
int main() {
std::string const input = "Vertices 4 { n"
" { 1, 2, 3 }, n"
" { 4, 5, 6 }, n"
" { 7, 8, 9 }, n"
" { 10, 11, 12 } n"
"}";
auto f(begin(input)), l(end(input));
grammar<std::string::const_iterator> g;
Geoset::Vertices vertices;
bool ok = qi::phrase_parse(f,l,g,qi::space,vertices);
if (ok) {
std::cout << "Parsed: " << vertices.size() << "n";
for (auto& v : vertices)
std::cout << boost::fusion::as_vector(v) << "n";
} else
std::cout << "Parse failedn";
if (f!=l)
std::cout << "Remaining input: '" << std::string(f,l) << "'n";
}
好的,通过编辑,这个问题变得可行。
确实同时具有std::array<>
和融合改编的(公共)基类(幸运的是¹!精神无法决定采用哪种属性分配路径。
所以通过以下方法修复它
-
告诉Spirit"这些不是你要找的机器人"(当它认为它看到的是一个容器时):
namespace boost { namespace spirit { namespace traits { template <> struct is_container<wc3lib::mdlx::VertexData> : mpl::false_ { }; } } }
住在科里鲁
-
不是(公开)派生自 std::array
我想你可能想问问自己,首先继承std::array<>
的意义何在。现在定义顶点类型的方式明确地使它们成为非 POD,这意味着性能将受到影响。
考虑一下
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;
};
或
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> {
};
对于某些性能。实际上,我可能会写
template <typename T = float> struct Vertex3d {
T x, y, z;
};
¹ 相信我,您需要一个图书馆来诊断这种情况
相关文章:
- 从C++实例化QML
- 设计一个只能由特定类实例化的类(如果可能的话,通过make_unique)
- 如何创建一个空的全局类并在启动时实例化它
- 在两个类中共享相同的函数调用,并在不需要时避免空实例化
- 约束和显式模板实例化
- 为什么包含windows.h会产生语法错误,从而阻止类的实例化?(C2146,C2065)
- 对象实例化调用构造函数的次数太多
- 如何使用非默认构造函数实例化模板化类
- 静态数据成员模板专用化的实例化点在哪里
- 错误的cv::face FacemarkLBF实例化
- C++的解析器在可以区分比较和模板实例化之前会做什么?
- 为什么 gcc 和 clang 为函数模板的实例化生成不同的符号名称?
- 检查某些类型是否是模板类 std::optional 的实例化
- 我有一个对象,它将在整个程序的持续时间内实例化,但一个类成员不会,我应该动态分配它吗?
- 无法使用 SWIG 在 Python 中实例化C++类(获取属性错误)
- 模板化类构造函数的模板实例化
- 在 c++ 中的模板实例化中使用带有构造函数的类作为类型参数
- 受约束的成员函数和显式模板实例化
- 模棱两可的模板实例化
- 使用重复将灵气存储到 std::vector 中会导致模棱两可的类模板实例化