gpt4 book ai didi

c++ - Spirit.X3 使用 string_view 和名为 'insert' 的成员编译错误

转载 作者:太空宇宙 更新时间:2023-11-04 12:48:17 26 4
gpt4 key购买 nike

在 Stackoverflow 上有几个与使用 {boost, std}::string_view 相关的问答,例如:

llonesmiz 在 wandbox 写了一个例子用 boost 1.64 编译, 但因 boost 1.67 而失败现在与

    opt/wandbox/boost-1.67.0/gcc-7.3.0/include/boost/spirit/home/x3/support/traits/container_traits.hpp:177:15: error: 'class boost::basic_string_view<char, std::char_traits<char> >' has no member named 'insert'
c.insert(c.end(), first, last);
~~^~~~~~

我在项目中遇到了同样的错误。

问题也通过使用 std::string 引发即使明确使用 Sehe's as<> "directive" ,另见 wandbox :

    #include <iostream>
#include <string>
#include <string_view>

namespace boost { namespace spirit { namespace x3 { namespace traits {

template <typename It>
void move_to(It b, It e, std::string_view& v)
{
v = std::string_view(&*b, e-b);
}

} } } } // namespace boost


#include <boost/spirit/home/x3.hpp>


namespace boost { namespace spirit { namespace x3 { namespace traits {

template <>
struct is_substitute<raw_attribute_type, std::string_view> : boost::mpl::true_
{};

} } } } // namespace boost


namespace parser
{
namespace x3 = boost::spirit::x3;
using x3::char_;
using x3::raw;

template<typename T>
auto as = [](auto p) { return x3::rule<struct _, T>{ "as" } = x3::as_parser(p); };

const auto str = as<std::string_view>(raw[ +~char_('_')] >> '_');
const auto str_vec = *str;
}

int main()
{
std::string input = "hello_world_";

std::vector<std::string_view> strVec;
boost::spirit::x3::parse(input.data(), input.data()+input.size(), parser::str_vec, strVec);

for(auto& x : strVec) { std::cout << x << std::endl; }
}

据我所知,问题始于 boost 1.65。发生了什么变化以及如何修复它?

最后,我对sehe提到的连续存储的要求有疑问: 我理解这个要求,但是解析器可以违反这个吗? - 在我看来,即使在回溯时解析器也必须失败,所以这不可能发生。通过使用error_handler,指向string_view 的内存存储地址最终在解析级别有效。我的结论是,只要引用在这种情况下的范围内,就可以使用 string_view,不是吗?

最佳答案

这里的问题似乎与 is_container 有关特点:

template <typename T>
using is_container = mpl::bool_<
detail::has_type_value_type<T>::value &&
detail::has_type_iterator<T>::value &&
detail::has_type_size_type<T>::value &&
detail::has_type_reference<T>::value>;

在 Qi 中,那将是专门化的:

template <> struct is_container<std::string_view> : std::false_type {};

但是在 X3 中,它开始成为模板别名,无法专门化。

这是一个棘手的问题,因为似乎根本没有自定义点可以让 X3 执行我们在这里需要的操作。

解决方法

我试图深入挖掘。我还没有看到解决这个问题的“干净”方法。事实上,属性强制转换可以帮助,但是,如果您使用它来“缩短”导致匹配的启发式:

  • 该属性“像一个”“char”的容器
  • 解析器可以匹配这样的容器

在这种情况下,我们可以将解析器的属性强制设置为特别是不兼容,这样事情就会开始起作用了。

正确覆盖 move_to

这也是一个有争议的领域。只需添加重载,如:

template <typename It>
inline void move_to(It b, It e, std::string_view& v) {
v = std::string_view(&*b, std::distance(b,e));
}

不足以使其成为最佳重载。

基础模板是

template <typename Iterator, typename Dest>
inline void move_to(Iterator first, Iterator last, Dest& dest);

要真正让它坚持下去,我们需要特化。然而,特化和功能模板is not a good match .特别是,我们不能部分特化,因此我们最终将对模板参数进行硬编码:

template <>
inline void move_to<Iterator, std::string_view>(Iterator b, Iterator e, std::string_view& v) {
v = std::string_view(&*b, std::distance(b,e));
}

This is making me question whether move_to is "user-serviceable" at all, much like is_container<> above, it just seems not designed for extension.

I do realize I've applied it in the past myself, but I also learn as I go.

强制:入侵系统

而不是声明规则的属性 std::string_view (将 X3 的类型魔法室留给“做 正确的 事情”),让我们将 raw[] 的预期结果刻在石头上。 (并让 X3 使用 move_to 完成其余的魔术):

namespace parser {
namespace x3 = boost::spirit::x3;
const auto str
= x3::rule<struct _, boost::iterator_range<Iterator> >{"str"}
= x3::raw[ +~x3::char_('_')] >> '_';
const auto str_vec = *str;
}

这行得通。查看它 Live On Wandbox

打印

hello
world

备选

这看起来很脆弱。例如。如果你change Iterator to char const* 它会坏的(或者,use std::string const input = "hello_world_",但不是 both)。

这是一个更好的做法(我认为):

namespace boost { namespace spirit { namespace x3 {

template <typename Char, typename CharT, typename Iterator>
struct default_transform_attribute<std::basic_string_view<Char, CharT>, boost::iterator_range<Iterator>> {
using type = boost::iterator_range<Iterator>;

template <typename T> static type pre(T&&) { return {}; }

static void post(std::basic_string_view<Char, CharT>& sv, boost::iterator_range<Iterator> const& r) {
sv = std::basic_string_view<Char, CharT>(std::addressof(*r.begin()), r.size());
}
};

} } }

现在,唯一需要跳过的环节是规则声明中提到迭代器类型。你也可以隐藏它:

namespace parser {
namespace x3 = boost::spirit::x3;

template <typename It> const auto str_vec = [] {
const auto str
= x3::rule<struct _, boost::iterator_range<It> >{"str"}
= x3::raw[ +~x3::char_('_')] >> '_';
return *str;
}();
}

auto parse(std::string_view input) {
auto b = input.begin(), e = input.end();
std::vector<std::string_view> data;
parse(b, e, parser::str_vec<decltype(b)>, data);
return data;
}

int main() {
for(auto& x : parse("hello_world_"))
std::cout << x << "\n";
}

这立即表明它适用于非指针迭代器。

Note: for completeness you'd want to statically assert the iterator models the ContiguousIterator concept (c++17)

最终版上线

Live On Wandbox

#include <iostream>
#include <string>
#include <string_view>
#include <boost/spirit/home/x3.hpp>

namespace boost { namespace spirit { namespace x3 {

template <typename Char, typename CharT, typename Iterator>
struct default_transform_attribute<std::basic_string_view<Char, CharT>, boost::iterator_range<Iterator>> {
using type = boost::iterator_range<Iterator>;

template <typename T> static type pre(T&&) { return {}; }

static void post(std::basic_string_view<Char, CharT>& sv, boost::iterator_range<Iterator> const& r) {
sv = std::basic_string_view<Char, CharT>(std::addressof(*r.begin()), r.size());
}
};

} } }

namespace parser {
namespace x3 = boost::spirit::x3;

template <typename It> const auto str_vec = [] {
const auto str
= x3::rule<struct _, boost::iterator_range<It> >{"str"}
= x3::raw[ +~x3::char_('_')] >> '_';
return *str;
}();
}

auto parse(std::string_view input) {
auto b = input.begin(), e = input.end();
std::vector<std::string_view> data;
parse(b, e, parser::str_vec<decltype(b)>, data);
return data;
}

int main() {
for(auto& x : parse("hello_world_"))
std::cout << x << "\n";
}

关于c++ - Spirit.X3 使用 string_view 和名为 'insert' 的成员编译错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50310015/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com