如何从数组构造元组 [英] How to construct a tuple from an array

查看:159
本文介绍了如何从数组构造元组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在设计一个C ++库,该库从一些实验中读取报告数据的CSV文件,并进行一些汇总并输出pgfplots代码。我想使该库尽可能通用并且易于使用。我还想将其与CSV文件中表示的数据类型隔离,并让用户根据需要选择分析每一列的选项。我也想避免使用Boost Spirit Qi或其他重型解析器。

I am designing a C++ library that reads a CSV file of reported data from some experiment and does some aggregation and outputs a pgfplots code. I want to make the library as generic and easy to use as possible. I also want to isolate it from the data types that are represented in the CSV file and leave the option to user to parse each column as she desires. I also want to avoid Boost Spirit Qi or other heavy duty parser.

我拥有的简单解决方案是让用户为每个列创建一个类型,并使用一个构造函数取 char *。构造函数对其给定的值进行自己的解析,该值是数据中的一个单元格。然后,用户将类型列表传递给我;模式,代表一行数据中的类型。我使用此类型列表创建一个元组,其中元组的每个成员都负责解析自身。

The simple solution I have is for the user to create a type for each column, with a constructor that takes "char *". The constructor does its own parsing for the value it is given, which is one cell from the data. The user then passes me a list of types; the schema, representing the types in a line of data. I use this type list to create a tuple, in which every member of the tuple is responsible for parsing itself.

现在的问题是如何初始化(构造)该元组。当然,处理元组并不是一件容易的事,因为遍历元组的元素主要是编译时操作。我最初使用Boost Fusion来完成此任务。但是,我使用的函数(转换)虽然可能将元组作为输入(使用适当的适配器),但它似乎未返回元组。我需要将返回值设为元组,以便其他代码可以将其用作关联的类型到值容器(通过 std :: get< T> ),而仅使用标准工具,即不使用Boost。因此,我必须将Fusion的返回值转换为std :: tuple。

The problem now is how to initialise (construct) this tuple. Dealing with tuples is of course not straightforward since iterating over their elements is mostly a compile-time operation. I used Boost Fusion at first to achieve this task. However, the function I used (transform) although might take a tuple as input (with the appropriate adapter), it does not seem to return a tuple. I need the return value to be a tuple so some other code can use it as an associative type-to-value container (access it by type via std::get<T>), while using only standard tools, that is, without using Boost. So I had to convert whatever Fusion's transform returned into std::tuple.

我的问题是如何避免这种转换,更好的是如何完全避免Boost Fusion。

My question is how to avoid this conversion, and better yet how to avoid Boost Fusion completely.

想到的一个简单解决方案是使用std :: tuple的构造函数,并以某种方式将每个需要传递的元素 const *传递给它。但是,尽管可以使用一些复杂的基于模板的枚举技术来实现,但我想知道是否存在一种简单的类似于参数打包的方法,还是将值传递给a的各个元素的构造函数的更简单方法元组。

A simple solution that comes to mind is to use the constructor of std::tuple, and somehow pass each element its respective "const *" that it needs to construct. However, while this is possible using some complicated template-based enumeration techniques, I am wondering if there is a straightforward "parameter-pack"-like approach, or an even simpler way to pass the values to the constructors of the individual elements of a tuple.

为阐明我要查找的内容,请看以下这段代码。

To clarify what I am seeking, kindly take a look at this following code.

    #include <cstdio>
    #include <array>
    template <typename...> struct format {};
    template <typename...> struct file_loader {};
    template <typename... Format>
    struct
    file_loader<format<Format...> > {
        void load_file() {
            size_t strsize = 500u;
            char *str = new char[strsize]();

            auto is = fopen("RESULT","r");
            /* example of RESULT:
                 dataset2,0.1004,524288
                 dataset1,0.3253,4194304
            */
            while(getline(&str, &strsize, is) >= 0) {
                std::array<char*, 3> toks{};
                auto s = str;
                int i = 2;
                while(i --> 0)
                    toks[i] = strsep (&s, ",");
                toks[2] = strsep (&s, ",\n");

                std::tuple<Format...> the_line{ /* toks */ } ; // <-- HERE
                //// current solution:
                // auto the_line{
                // as_std_tuple( // <-- unnecessary conversion I'd like to avoid
                //  boost::fusion::transform(boost::fusion::zip(types, toks), boost::fusion::make_fused( CAST() ))
                //  )};


                // do something with the_line
            }
        }
    };

    #include <string>
    class double_type {
    public:
        double_type() {}
        double_type(char const *token) { } // strtod
    };
    class int_type {
    public:
        int_type() {}
        int_type(char const *token) { } // strtoul
    };

    int main(int argc, char *argv[]) {
        file_loader< format< std::string,
                             double_type,
                             int_type > >
        {}.load_file();


        return 0;
    }

我在评论中将有趣的行突出显示为 HERE。

I've highlighted the interesting line as "HERE" in a comment.

我的问题正好是:


有没有一种构造std的方法:: tuple实例(具有不同类型的
类型,每种类型都可以从 char *隐式转换),并具有
自动存储持续时间(在堆栈上),该存储时间来自 std :: array< ; char *,N>
其中N等于该元组的大小?

Is there a way to construct a std::tuple instance (of heterogeneous types, each of which is implicitly convertible from "char *") with automatic storage duration (on the stack) from a std::array<char *, N>, where N equals the size of that tuple?

我正在寻找的答案应该


  1. 避免Boost Fusion

  2. (简单性条件)避免使用大于5行基于样板模板的枚举代码

  3. 或者,显示了为什么在C ++ 14标准中无法做到这一点

答案可以使用C ++ 17构造,我不在乎。

The answer can use C++17 constructs, I wouldn't mind.

谢谢,

推荐答案

与所有涉及 std :: tuple ,使用 index_sequence 为您提供参数包以使用以下方式对数组建立索引:

As with all questions involving std::tuple, use index_sequence to give you a parameter pack to index the array with:

template <class... Formats, size_t N, size_t... Is>
std::tuple<Formats...> as_tuple(std::array<char*, N> const& arr,
                                std::index_sequence<Is...>)
{
    return std::make_tuple(Formats{arr[Is]}...);
}

template <class... Formats, size_t N,
          class = std::enable_if_t<(N == sizeof...(Formats))>>
std::tuple<Formats...> as_tuple(std::array<char*, N> const& arr)
{
    return as_tuple<Formats...>(arr, std::make_index_sequence<N>{});
}

您将使用哪种方式:

std::tuple<Format...> the_line = as_tuple<Format...>(toks);

这篇关于如何从数组构造元组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆