简体   繁体   English

在编译时用已知的N重复到std :: tuple

[英]repeat to std::tuple with known N at compile time

i want to parse a at compile time specified number of elements. 我想在编译时解析指定数量的元素。 I've tried the repeat()[] directive. 我已经尝试了repeat()[]指令。 The following code shows my case: 以下代码显示了我的情况:

 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); 

The compiler error message: 编译器错误消息:

error: static assertion failed: Expecting a single element fusion sequence
             static_assert(traits::has_size<Attribute, 1>::value

It works if i would write it out: 如果我写出来的话它会工作:

parse(std::begin(str), std::end(str), float_ >> ' ' >> float_ >> ' ' >> float_ ] , tup);

but with a large number of elements it is confusion. 但是由于存在大量元素,这是一种混乱。

Is there a way to shorten the grammar with a ' repeat ' directive ? 有没有办法用' 重复 '指令缩短语法?

As you can see here the synthesized attribute of x3::repeat(3)[x3::float_] is a vector<float> and that does not match your attribute (basically a fusion sequence of size 3). 正如您在这里看到的, x3::repeat(3)[x3::float_]的合成属性是一个vector<float> ,它与您的属性(基本上是大小为3的融合序列)不匹配。 Note that the synthesized attribute does not depend on the value you pass. 请注意,合成属性不依赖于您传递的值。

In order to get what you want you'll need another directive, one which type does depend on the value you pass. 为了获得你想要的东西,你需要另一个指令,一个类型取决于你传递的值。 This directive would then generate a sequence where it's subject is repeated N times (simply "delegating" the work to x3::sequence would make sure that everything works correctly in regards to attribute propagation). 然后,该指令将生成一个序列,其中主题被重复N次(简单地将工作“委托”到x3::sequence将确保一切在属性传播方面正常工作)。 I can think of at least two ways this could work: something like repeat<N>[parser] or something like repeat(integral_constant<int,N>)[parser] . 我可以想到至少有两种方法可以解决这个问题: repeat<N>[parser]或像repeat(integral_constant<int,N>)[parser] In the code below I have chosen the second approach using boost::hana::integral_constant , which allows you to use: 在下面的代码中,我选择了使用boost::hana::integral_constant的第二种方法,它允许您使用:

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

Full Code (Running on WandBox) 完整代码 (在WandBox上运行)

custom_repeat.hpp 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 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) ] );

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Range-v3 view :: sliding(n)返回元组(如果在编译时已知n) - Range-v3 view::sliding(n) to return tuple (if n known at compile time) 在编译时检测 std::tuple 中的类型包含 - Detecting type inclusion in std::tuple at compile time 如何在编译时查询 constexpr std::tuple? - How to query a constexpr std::tuple at compile time? 任意,但编译时已知数量的类型的元组 - Tuple of an arbitrary, but compile-time-known number of types 如何在编译时使用 std::make_tuple? - How can I use std::make_tuple at compile time? 如何在C ++ 17中创建在编译时已知大小的修订类型元组? - How to create a tuple of fix types whose size is a known at compile time in C++17? 如何在C ++中生成0到N的size_t包,其中在编译时已知N - How to generate a pack of size_t from 0 to N in C++ where N is known at compile time 从编译时已知的日历日期创建`std::chrono::time_point` - Creating a `std::chrono::time_point` from a calendar date known at compile time 将编译时已知函数参数转换为std :: integral_constant的有效方法 - Efficient way to convert a compile time known function argument to a std::integral_constant 如何测试具有编译时已知长度的 std::initializer_list 的 ctor? - How to test a ctor taking std::initializer_list with a compile-time known length?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM