组合`%`和可选后缀时,自动属性传播有时不起作用

时间:2018-08-01 20:57:17

标签: c++ boost boost-spirit boost-spirit-x3

在clang 3.8.0和GCC 5.4上都使用boost 1.61,在编译以下代码时出现错误:

#include <string>
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/adapted.hpp>
#include <tuple>
#include <vector>
#include <cassert>

void do_test(std::string input)
{
    namespace x3 = boost::spirit::x3;

    using x3::char_;
    using x3::lit;
    using x3::alpha;

    auto const word = +(alpha - ' ');


    auto first = begin(input);
    auto last = end(input);

    //this works
    {
        auto const& g = word;
        std::string out;
        x3::parse(first, last, g, out);
    }
    {
        auto const& g = (word % ',');
        std::vector<std::string> out;
        x3::parse(first, last, g, out);
    }
    {
        auto const& g = lit('/') >> (word % ',');
        std::vector<std::string> out;
        x3::parse(first, last, g, out);
    }
    {
        auto const& g = -(word % ',');
        std::vector<std::string> out;
        x3::parse(first, last, g, out);
    }
    {
        auto const& g = -(lit('/') >> (word % ','));
        std::vector<std::string> out;
        x3::parse(first, last, g, out);
    }
    {
        auto const& g = -(lit('/') >> (word % ',') >> -lit('/'));
        std::vector<std::string> out;
        x3::parse(first, last, g, out);
    }
    {
        auto const& g = word >> lit(':') >> word;
        std::tuple<std::string, std::string> out;
        x3::parse(first, last, g, out);
    }
    {
        auto const& g = word >> lit(':') >> -(word % ',');
        std::tuple<std::string, std::vector<std::string>> out;
        x3::parse(first, last, g, out);
    }
    //but this fails.
    {
        auto const& g = word >> lit(':') >> -(lit('/') >> (word % ',') >> -lit('/'));
        std::tuple<std::string, std::vector<std::string>> out;
        x3::parse(first, last, g, out);
    }
    {
        auto const& g = word >> lit(':') >> -((word % ',') >> -lit('/'));
        std::tuple<std::string, std::vector<std::string>> out;
        x3::parse(first, last, g, out);
    }

}

,并显示以下错误消息:

FAILED: /usr/bin/x86_64-linux-gnu-g++   -I../ext/boost-spirit/include -g -ggdb3   -fPIC -std=gnu++14 -MD -MT src/rtsp-header-parse/CMakeFiles/rtsp-header-parse.dir/rtsp-header-parse/test.cpp.o -MF src/rtsp-header-parse/CMakeFiles/rtsp-header-parse.dir/rtsp-header-parse/test.cpp.o.d -o src/rtsp-header-parse/CMakeFiles/rtsp-header-parse.dir/rtsp-header-parse/test.cpp.o -c ../src/rtsp-header-parse/rtsp-header-parse/test.cpp
In file included from ../ext/boost-spirit/include/boost/spirit/home/x3/auxiliary/any_parser.hpp:15:0,
                 from ../ext/boost-spirit/include/boost/spirit/home/x3/auxiliary.hpp:11,
                 from ../ext/boost-spirit/include/boost/spirit/home/x3.hpp:14,
                 from ../src/rtsp-header-parse/rtsp-header-parse/test.cpp:2:
../ext/boost-spirit/include/boost/spirit/home/x3/support/traits/container_traits.hpp: In instantiation of ‘struct boost::spirit::x3::traits::container_value<boost::fusion::iterator_range<boost::fusion::std_tuple_iterator<std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, 1>, boost::fusion::std_tuple_iterator<std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, 2> >, void>’:
../ext/boost-spirit/include/boost/spirit/home/x3/core/detail/parse_into_container.hpp:227:12:   required from ‘struct boost::spirit::x3::detail::parser_attr_is_substitute_for_container_value<boost::spirit::x3::plus<boost::spirit::x3::difference<boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::alpha_tag>, boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type> > >, boost::fusion::iterator_range<boost::fusion::std_tuple_iterator<std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, 1>, boost::fusion::std_tuple_iterator<std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, 2> >, boost::spirit::x3::unused_type>’
../ext/boost-spirit/include/boost/mpl/aux_/nested_type_wknd.hpp:26:31:   required from ‘struct boost::mpl::aux::nested_type_wknd<boost::spirit::x3::detail::parser_attr_is_substitute_for_container_value<boost::spirit::x3::plus<boost::spirit::x3::difference<boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::alpha_tag>, boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type> > >, boost::fusion::iterator_range<boost::fusion::std_tuple_iterator<std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, 1>, boost::fusion::std_tuple_iterator<std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, 2> >, boost::spirit::x3::unused_type> >’
../ext/boost-spirit/include/boost/mpl/not.hpp:39:8:   required from ‘struct boost::mpl::not_<boost::spirit::x3::detail::parser_attr_is_substitute_for_container_value<boost::spirit::x3::plus<boost::spirit::x3::difference<boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::alpha_tag>, boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type> > >, boost::fusion::iterator_range<boost::fusion::std_tuple_iterator<std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, 1>, boost::fusion::std_tuple_iterator<std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, 2> >, boost::spirit::x3::unused_type> >’
../ext/boost-spirit/include/boost/mpl/aux_/nested_type_wknd.hpp:26:31:   required from ‘struct boost::mpl::aux::nested_type_wknd<boost::mpl::not_<boost::spirit::x3::detail::parser_attr_is_substitute_for_container_value<boost::spirit::x3::plus<boost::spirit::x3::difference<boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::alpha_tag>, boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type> > >, boost::fusion::iterator_range<boost::fusion::std_tuple_iterator<std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, 1>, boost::fusion::std_tuple_iterator<std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, 2> >, boost::spirit::x3::unused_type> > >’
../ext/boost-spirit/include/boost/mpl/aux_/preprocessed/gcc/or.hpp:23:8:   required from ‘struct boost::mpl::aux::or_impl<false, boost::mpl::not_<boost::spirit::x3::detail::parser_attr_is_substitute_for_container_value<boost::spirit::x3::plus<boost::spirit::x3::difference<boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::alpha_tag>, boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type> > >, boost::fusion::iterator_range<boost::fusion::std_tuple_iterator<std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, 1>, boost::fusion::std_tuple_iterator<std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, 2> >, boost::spirit::x3::unused_type> >, mpl_::bool_<false>, mpl_::bool_<false>, mpl_::bool_<false> >’
../ext/boost-spirit/include/boost/mpl/aux_/preprocessed/gcc/or.hpp:48:8:   [ skipping 7 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
../ext/boost-spirit/include/boost/spirit/home/x3/core/proxy.hpp:42:73:   required from ‘bool boost::spirit::x3::proxy<Subject, Derived>::parse(Iterator&, const Iterator&, const Context&, RuleContext&, Attribute&) const [with Iterator = __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >; Context = boost::spirit::x3::unused_type; RuleContext = const boost::spirit::x3::unused_type; Attribute = boost::fusion::iterator_range<boost::fusion::std_tuple_iterator<std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, 1>, boost::fusion::std_tuple_iterator<std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, 2> >; Subject = boost::spirit::x3::sequence<boost::spirit::x3::list<boost::spirit::x3::plus<boost::spirit::x3::difference<boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::alpha_tag>, boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type> > >, boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type> >, boost::spirit::x3::optional<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type> > >; Derived = boost::spirit::x3::optional<boost::spirit::x3::sequence<boost::spirit::x3::list<boost::spirit::x3::plus<boost::spirit::x3::difference<boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::alpha_tag>, boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type> > >, boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type> >, boost::spirit::x3::optional<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type> > > >]’
../ext/boost-spirit/include/boost/spirit/home/x3/operator/detail/sequence.hpp:312:13:   required from ‘bool boost::spirit::x3::detail::parse_sequence(const Parser&, Iterator&, const Iterator&, const Context&, RContext&, Attribute&, boost::spirit::x3::traits::tuple_attribute) [with Parser = boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::plus<boost::spirit::x3::difference<boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::alpha_tag>, boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type> > >, boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type> >, boost::spirit::x3::optional<boost::spirit::x3::sequence<boost::spirit::x3::list<boost::spirit::x3::plus<boost::spirit::x3::difference<boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::alpha_tag>, boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type> > >, boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type> >, boost::spirit::x3::optional<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type> > > > >; Iterator = __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >; Context = boost::spirit::x3::unused_type; RContext = const boost::spirit::x3::unused_type; Attribute = std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >]’
../ext/boost-spirit/include/boost/spirit/home/x3/operator/sequence.hpp:44:42:   required from ‘bool boost::spirit::x3::sequence<Left, Right>::parse(Iterator&, const Iterator&, const Context&, RContext&, Attribute&) const [with Iterator = __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >; Context = boost::spirit::x3::unused_type; RContext = const boost::spirit::x3::unused_type; Attribute = std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >; Left = boost::spirit::x3::sequence<boost::spirit::x3::plus<boost::spirit::x3::difference<boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::alpha_tag>, boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type> > >, boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type> >; Right = boost::spirit::x3::optional<boost::spirit::x3::sequence<boost::spirit::x3::list<boost::spirit::x3::plus<boost::spirit::x3::difference<boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::alpha_tag>, boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type> > >, boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type> >, boost::spirit::x3::optional<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type> > > >]’
../ext/boost-spirit/include/boost/spirit/home/x3/core/parse.hpp:35:68:   required from ‘bool boost::spirit::x3::parse_main(Iterator&, Iterator, const Parser&, Attribute&) [with Iterator = __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >; Parser = boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::plus<boost::spirit::x3::difference<boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::alpha_tag>, boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type> > >, boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type> >, boost::spirit::x3::optional<boost::spirit::x3::sequence<boost::spirit::x3::list<boost::spirit::x3::plus<boost::spirit::x3::difference<boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::alpha_tag>, boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type> > >, boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type> >, boost::spirit::x3::optional<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type> > > > >; Attribute = std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >]’
../ext/boost-spirit/include/boost/spirit/home/x3/core/parse.hpp:47:26:   required from ‘bool boost::spirit::x3::parse(Iterator&, Iterator, const Parser&, Attribute&) [with Iterator = __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >; Parser = boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::plus<boost::spirit::x3::difference<boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::alpha_tag>, boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type> > >, boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type> >, boost::spirit::x3::optional<boost::spirit::x3::sequence<boost::spirit::x3::list<boost::spirit::x3::plus<boost::spirit::x3::difference<boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::alpha_tag>, boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type> > >, boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type> >, boost::spirit::x3::optional<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type> > > > >; Attribute = std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >]’
../src/rtsp-header-parse/rtsp-header-parse/test.cpp:72:38:   required from here
../ext/boost-spirit/include/boost/spirit/home/x3/support/traits/container_traits.hpp:76:12: error: no type named ‘value_type’ in ‘struct boost::fusion::iterator_range<boost::fusion::std_tuple_iterator<std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, 1>, boost::fusion::std_tuple_iterator<std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, 2> >’
     struct container_value
            ^
In file included from ../ext/boost-spirit/include/boost/spirit/home/x3/directive/expect.hpp:12:0,
                 from ../ext/boost-spirit/include/boost/spirit/home/x3/auxiliary/guard.hpp:11,
                 from ../ext/boost-spirit/include/boost/spirit/home/x3/auxiliary.hpp:13,
                 from ../ext/boost-spirit/include/boost/spirit/home/x3.hpp:14,
                 from ../src/rtsp-header-parse/rtsp-header-parse/test.cpp:2:
...

我很好奇为什么%运算符与包含可选参数和内部顺序部分的组合会导致编译失败。即:为什么-(word % ',')可以正常工作,但是-((word % ',') >> lit('/'))无法解析为子表达式?同时,为什么在删除前缀词并将其直接解析为std::vector<std::string>时起作用?

我还尝试解析为boost::mpl::vector<std::string, std::vector<std::string>>并得到相同的错误。

1 个答案:

答案 0 :(得分:1)

最简单的答案是:魔术。

稍长一点的答案是:有时将单元素序列属性视为它们的单个元素。

您正在击败这两种情况之间的优势,并发现在各个实现点做出的“启发式”选择会泄漏“魔术”。

修复问题

我不确定您使用的是哪个版本以及正在测试的输入内容。实际上,源代码提出了一些问题:

  • alpha - ' 'alpha的语气(''不是alpha)
  • 这意味着您可能希望单词由空格分隔,除非您还有一个分隔符,并且word放在lexeme[]下(请参见{ {3}})
  • 您根本没有检查结果。这意味着事物可能无法解析任何东西,或者只能解析部分输入。 “编译”并不像“工作”那么有趣

鉴于此,在所有示例都能正常工作的情况下,这是我的最佳猜测,我希望能为您提供一些想法:

演示

#include <boost/fusion/adapted.hpp>
#include <boost/spirit/home/x3.hpp>
#include <tuple>
#include <string>
#include <vector>

#include <iostream>
#include <iomanip>

namespace x3 = boost::spirit::x3;

namespace {
    std::ostream& dump(std::ostream& os, std::string const& s) {
        return os << std::quoted(s);
    }

    template <typename T>
    std::ostream& dump(std::ostream& os, std::vector<T> const& v) {
        os << "vector{ ";
        for (auto& el : v)
            dump(os, el) << ", ";
        return os << "}";
    }

    template <typename A, typename B>
    std::ostream& dump(std::ostream& os, std::tuple<A, B> const& tuple) {
        dump(os << "\n  * tuple[0]: ", std::get<0>(tuple));
        dump(os << "\n  * tuple[1]: ", std::get<1>(tuple));
        return os;
    }
}

template <typename Out, typename It, typename Grammar>
void do_test(It f, It l, Grammar const& g) {
    std::cout << " == input = " << std::quoted(std::string(f,l)) << "\n";
    Out out{};
    bool ok = x3::parse(f, l, g, out);

    std::cout << " -- ok = " << std::boolalpha << ok << "\n";
    dump(std::cout << " -- out = ", out) << "\n";
    if (f!=l)
        std::cout << " -- remaining unparsed: " << std::quoted(std::string(f,l)) << "\n";
}

namespace testing {
    #define TESTCASE(T, P)                                                                                  \
        do {                                                                                                \
            std::cout << "\n## " << __FUNCTION__ << " line: " << __LINE__ << " parser: " << std::quoted(std::string(#P)) << "\n";  \
            auto f = begin(input), l = end(input);                                                          \
            do_test<T>(f, l, P);                                                                            \
        } while (0)

    using std::string;
    using string_vec       = std::vector<string>;
    using string_string    = std::tuple<string, string>;
    using string_stringvec = std::tuple<string, string_vec>;

    static auto const word
        = x3::rule<struct word_, std::string> {"word"}
        = x3::graph >> *(x3::graph - ':' - ',' - '/')
        ;

    void value_only(std::string const& input) {
        TESTCASE(string, word);
        TESTCASE(string_vec, (word % ','));
        TESTCASE(string_vec, '/' >> (word % ','));
        TESTCASE(string_vec, -(word % ','));
        TESTCASE(string_vec, -('/' >> (word % ',')));
        TESTCASE(string_vec, -('/' >> (word % ',') >> -x3::lit('/')));
    }

    void key_value(std::string const& input) {
        TESTCASE(string_string,    word >> ':' >> word);
        TESTCASE(string_stringvec, word >> ':' >> -(word % ','));
        TESTCASE(string_stringvec, word >> ':' >> -('/' >> (word % ',') >> -x3::lit('/')));
        TESTCASE(string_stringvec, word >> ':' >> -((word % ',') >> -x3::lit('/')));
    }

    #undef TESTCASE
}

int main() {
    testing::value_only("/other,words/");
    testing::key_value("hello:/other,words/");
}

提升1.66的解决方法?

您可以使用其他规则强制将“值”部分设为vector<string>。最简单的方法:

commenting out those two cases works

void key_value(std::string const& input) {
    TESTCASE(string_string,    word >> ':' >> word);
    TESTCASE(string_stringvec, word >> ':' >> -(word % ','));
    auto asvec = [](auto p) {
        return x3::rule<struct asvec_, string_vec> {"asvec"} = p;
    };
    TESTCASE(string_stringvec, word >> ':' >> asvec(-('/' >> (word % ',') >> -x3::lit('/'))));
    TESTCASE(string_stringvec, word >> ':' >> asvec(-((word % ',') >> -x3::lit('/'))));
}

输出

为完整起见,程序打印:

## value_only line: 64 parser: "word"
 == input = "/other,words/"
 -- ok = true
 -- out = "/other"
 -- remaining unparsed: ",words/"

## value_only line: 65 parser: "(word % ',')"
 == input = "/other,words/"
 -- ok = true
 -- out = vector{ "/other", "words", }
 -- remaining unparsed: "/"

## value_only line: 66 parser: "'/' >> (word % ',')"
 == input = "/other,words/"
 -- ok = true
 -- out = vector{ "other", "words", }
 -- remaining unparsed: "/"

## value_only line: 67 parser: "-(word % ',')"
 == input = "/other,words/"
 -- ok = true
 -- out = vector{ "/other", "words", }
 -- remaining unparsed: "/"

## value_only line: 68 parser: "-('/' >> (word % ','))"
 == input = "/other,words/"
 -- ok = true
 -- out = vector{ "other", "words", }
 -- remaining unparsed: "/"

## value_only line: 69 parser: "-('/' >> (word % ',') >> -x3::lit('/'))"
 == input = "/other,words/"
 -- ok = true
 -- out = vector{ "other", "words", }

## key_value line: 73 parser: "word >> ':' >> word"
 == input = "hello:/other,words/"
 -- ok = true
 -- out = 
  * tuple[0]: "hello"
  * tuple[1]: "/other"
 -- remaining unparsed: ",words/"

## key_value line: 74 parser: "word >> ':' >> -(word % ',')"
 == input = "hello:/other,words/"
 -- ok = true
 -- out = 
  * tuple[0]: "hello"
  * tuple[1]: vector{ "/other", "words", }
 -- remaining unparsed: "/"

## key_value line: 78 parser: "word >> ':' >> asvec(-('/' >> (word % ',') >> -x3::lit('/')))"
 == input = "hello:/other,words/"
 -- ok = true
 -- out = 
  * tuple[0]: "hello"
  * tuple[1]: vector{ "other", "words", }

## key_value line: 79 parser: "word >> ':' >> asvec(-((word % ',') >> -x3::lit('/')))"
 == input = "hello:/other,words/"
 -- ok = true
 -- out = 
  * tuple[0]: "hello"
  * tuple[1]: vector{ "/other", "words", }