如何从数组

时间:2016-05-04 13:54:34

标签: c++ templates c++11 c++14 variadic-templates

我正在设计一个C ++库,它从某些实验中读取报告数据的CSV文件,并进行一些聚合并输出pgfplots代码。我想使库尽可能通用且易于使用。我还希望将其与CSV文件中表示的数据类型隔离开来,并将选项留给用户按照自己的意愿解析每个列。我也想避免使用Boost Spirit Qi或其他重型解析器。

我所拥有的简单解决方案是让用户为每个列创建一个类型,其构造函数采用" char *"。构造函数自己解析它给出的值,它是数据中的一个单元格。然后用户传给我一个类型列表;模式,表示一行数据中的类型。我使用这个类型列表来创建一个元组,其中元组的每个成员都负责解析自身。

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

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

一个简单的解决方案是使用std :: tuple的构造函数,并以某种方式将每个元素传递给它们各自的&#34; const *&#34;它需要构建。然而,尽管使用一些复杂的基于模板的枚举技术是可能的,但我想知道是否有一种简单的&#34;参数包&#34;类方法,或者更简单的方法将值传递给构造函数元组的各个元素。

为了澄清我在寻找的内容,请仔细阅读以下代码。

    #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;
    }

我突出了有趣的一句话&#34; HERE&#34;在评论中。

我的问题恰恰是:

  

有没有办法构建一个std :: tuple实例(异构的   类型,每个类型都可以隐式转换为&#34; char *&#34;)   来自std::array<char *, N>的自动存储持续时间(在堆栈上),   其中N等于那个元组的大小?

我正在寻找答案

  1. 避免增强融合
  2. (简单条件)避免使用超过5行基于样板模板的枚举代码
  3. 或者,说明为什么在C ++ 14标准中无法做到这一点
  4. 答案可以使用C ++ 17构造,我不会介意。

    谢谢,

1 个答案:

答案 0 :(得分:14)

与涉及std::tuple的所有问题一样,使用index_sequence为您提供一个参数包,用于索引数组:

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