【问题标题】:How to construct a tuple from an array如何从数组构造元组
【发布时间】:2016-08-30 00:27:06
【问题描述】:

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

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

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

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

想到的一个简单解决方案是使用 std::tuple 的构造函数,并以某种方式将每个元素传递给它需要构造的相应“const *”。然而,虽然这可以使用一些复杂的基于模板的枚举技术,但我想知道是否有一种简单的“参数包”式方法,或者更简单的方法将值传递给单个元素的构造函数元组。

为了澄清我在寻找什么,请查看以下代码。

    #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”。

我的问题恰恰是:

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

我正在寻找的答案应该是

  1. 避免加速融合
  2. (简单条件)避免使用超过 5 行的样板基于模板的枚举代码
  3. 另外,说明为什么在 C++14 标准中无法做到这一点

答案可以使用 C++17 构造,我不介意。

谢谢你,

【问题讨论】:

  • 想知道Fusion的transform是否可以直接返回std::tuple。
  • while(i --&gt; 0) 请不要这样做。你会吓到孩子的。 :)
  • @erip 我实际上并没有使用它。在我的真实代码中,我使用的是 boost irange。我只是不想从我的代码中带来所有非标准的东西和包括在这里。你不觉得 irange 会更可怕吗?
  • 我觉得您可以使用可变参数模板扩展 toks 并将其转发给 std::tie。只是一个想法。 :)
  • @erip 我想到了,但我不清楚如何使用可变参数模板扩展 toks。

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


【解决方案1】:

与所有涉及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);

【讨论】:

  • 确实很好。 +1 为 enable_if 健全性检查 :) !
  • 我可能会在里面使用static_assert。但是+1。
  • @T.C.您认为何时使用static_assert() 和何时使用enable_if 之间的规则是什么?
  • @Barry 任何人可能合理地想要在 => enable_if 上使用 is_detected(或等效概念)的任何东西,这样我们就不会撒谎。否则,static_assert 会提供更好的错误消息。当然,这有点主观。
  • 只是一个小问题,也许它可以为数组类型更通用一点 (e.g.)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-03
  • 2017-08-27
  • 2022-12-06
  • 2014-02-01
  • 2016-11-02
  • 1970-01-01
相关资源
最近更新 更多