c++ - 在编译时重复到已知N的std::tuple

标签 c++ boost-spirit-x3

我想在编译时解析指定数量的元素。我已经尝试过repeat()[]指令。以下代码显示了我的情况:

 using namespace x3;
 std::tuple<float, float, float> tup;
 std::string str{"0.3 0.2 0.1"};
 auto ret = parse(std::begin(str), std::end(str), repeat(3)[ float_ >> (' ' | eol) ] , tup); 

编译器错误信息:
error: static assertion failed: Expecting a single element fusion sequence
             static_assert(traits::has_size<Attribute, 1>::value

如果我写出来,它会工作:
parse(std::begin(str), std::end(str), float_ >> ' ' >> float_ >> ' ' >> float_ ] , tup);

但是元素很多,很困惑。

有没有一种方法可以通过“重复”指令来缩短语法?

最佳答案

如您所见herex3::repeat(3)[x3::float_]的综合属性是vector<float>,并且与您的属性不匹配(基本上是大小为3的融合序列)。请注意,综合属性不取决于您传递的值。

为了获得所需的内容,您需要另一个指令,该指令的类型确实取决于您传递的值。然后,此伪指令将生成一个序列,在此序列中,其主题要重复N次(将工作“委派”给x3::sequence可以确保在属性传播方面一切正常)。我可以想到至少有两种方法可以起作用:类似于repeat<N>[parser]或类似repeat(integral_constant<int,N>)[parser]的东西。在下面的代码中,我选择了第二种方法,使用 boost::hana::integral_constant ,它允许您使用:

custom::repeat(3_c)[ x3::float_ >> (' ' | x3::eol | x3::eoi) ]

完整代码 (Running on WandBox)

custom_repeat.hpp

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

namespace custom
{
    struct repeat_gen
    {
        template <int Size>
        struct repeat_gen_lvl1
        {

            //using overloads with integral constants to avoid needing to partially specialize a function

            //this actually builds the sequence of parsers
            template <typename Parser,int N>
            auto generate_sequence(Parser const& parser, std::integral_constant<int,N>) const
            {
                return generate_sequence(parser,std::integral_constant<int,N-1>{}) >> parser;
            }

            template <typename Parser>
            auto generate_sequence(Parser const parser,std::integral_constant<int,1>) const
            {
                return parser;
            }

            template<typename Subject>
            auto operator[](Subject const& subject) const
            {
                //here the actual sequence is generated
                return generate_sequence(boost::spirit::x3::as_parser(subject), std::integral_constant<int,Size>{});
            }
        };

        template <typename IntConstant>
        repeat_gen_lvl1<int(IntConstant::value)>
        operator()(IntConstant) const
        {
            //returns an object that know the size of the wanted sequence and has an operator[] that will capture the subject
            return {};
        }

        template <typename IntegerType, typename Enable=std::enable_if_t<std::is_integral<IntegerType>::value> >
        auto operator()(IntegerType n) const
        {
            return boost::spirit::x3::repeat(n);
        }
    };

    //this object's only purpose is having an operator()
    auto const repeat = repeat_gen{};
}

main.cpp

#include <iostream>

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

#include <boost/fusion/include/std_tuple.hpp>
#include <boost/fusion/include/std_pair.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/fusion/include/as_vector.hpp>
#include <boost/fusion/include/is_sequence.hpp>

#include <boost/hana/integral_constant.hpp>

#include <boost/mpl/int.hpp>

#include "custom_repeat.hpp"

namespace x3 = boost::spirit::x3;

using namespace boost::hana::literals;

template <typename T>
void print_attr(const std::vector<T>& vec)
{
    std::cout << "Vector: ";
    for(const auto& elem : vec)
        std::cout << "[" << elem << "]";
}

template <typename Sequence, typename Enable=std::enable_if_t<boost::fusion::traits::is_sequence<Sequence>::value> >
void print_attr(const Sequence& seq)
{
    std::cout << "Sequence: " << boost::fusion::as_vector(seq);
}

template <typename Attr,typename Parser>
void parse(const std::string& str, const Parser& parser)
{
    Attr attr;
    std::string::const_iterator iter = std::begin(str), end = std::end(str);
    bool ret = x3::parse(iter, end, parser, attr);

    if(ret && (iter==end))
    {
        std::cout << "Success.\n";
        print_attr(attr);
        std::cout << std::endl;
    }
    else
    {
        std::cout << "Something failed. Unparsed: ->|" << std::string(iter,end) << "|<-" << std::endl;
    }
}

struct float_holder
{
    float val;
};

BOOST_FUSION_ADAPT_STRUCT(float_holder,val);

int main()
{
    boost::mpl::int_<2> two;
    std::integral_constant<int,1> one;

    parse<std::tuple<float,float,float> >("0.3 0.2 0.1", custom::repeat(3_c)[ x3::float_ >> (' ' | x3::eol | x3::eoi) ] );
    parse<std::pair<float,float> >("0.2 0.1", custom::repeat(two)[ x3::float_ >> (' ' | x3::eol | x3::eoi) ] );
    parse<float_holder>("0.1", custom::repeat(one)[ x3::float_ >> (' ' | x3::eol | x3::eoi) ] );

    parse<std::vector<float> >("0.3 0.2 0.1", custom::repeat(3)[ x3::float_ >> (' ' | x3::eol | x3::eoi) ] );

}

关于c++ - 在编译时重复到已知N的std::tuple,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39050807/

相关文章:

c++ - 从模板类覆盖纯虚函数

c++ - Boost Spirit X3 跳过解析器实现?

c++ - 如何以 boost spirit 允许好的空间并禁止坏的空间

c++ - Stringify 和 Unstringify 模板参数

c++ - 两个 std::List 之间的距离

c++ - Spirit X3,如何让属性类型匹配规则类型?

c++ - 使用 boost spirit x3 分离解析器时出现链接错误

c++ - 语义操作(使用 _val 和 _attr)如何影响 %= 和 x3::rule 的 force_attribute=true 的规则定义?

c++ - 检查 C++ 代码中设置的编译器标志

c++ - 如何暂停 Boost 单元测试?