【问题标题】:Generate a std::tuple from standard container从标准容器生成 std​​::tuple
【发布时间】:2015-08-31 14:14:15
【问题描述】:

是否有一种可移植的方式从容器的内容中生成std::tuple(实际上是std::array)?这样的元组将允许std::apply 从容器中提取函数参数。

我使用尾递归的第一次尝试失败并出现编译器错误:“递归模板实例化超过最大值...”。

我的第二次尝试(std::for_each 带有一个可变 lambda 持有元组)无法完全编译并获得所需的结果。

我认为类似于boost::mpl 如何处理可变参数元函数(即使用boost::preprocessor 的魔术)的某些东西可以工作——但这​​就是c++03。我希望有更好的解决方案。

函数签名看起来像:

std::list<int> args_as_list = {1, 2, 3, 4};
auto tpl = args_as_tuple(args_as_list);

tpl 的类型是std::array&lt;int const, 4&gt;

【问题讨论】:

  • std::tuple (真的是一个 std::array) 你是什么意思? std::uple 和 std::array 相同。
  • Tuple 是编译时的事情,你无法在编译时知道列表中有多少 elem。无论如何,您可以使用 std::llist::value_type
  • 一个std::array支持std::tuple接口。显然容器中的所有元素都是同一类型container::value_type。所以一个真正的元组,或者一个std::array 都可以。

标签: c++ c++11 boost-mpl


【解决方案1】:

简答:,不可能。

解释:std::tuplestd::array 都需要关于元素数量的编译时间信息。 std::liststd::vector 只能提供关于元素计数的运行时信息。

您的 args_as_tuple 函数必须是一个模板,将预期参数的数量作为模板参数 (args_as_tuple&lt;4&gt;(args_as_list))。

虽然必须将参数数量作为模板参数似乎很苛刻,但在您的示例中,这是非常明显的 - 函数参数的数量(提供给 std::apply 的函数)也必须在编译时知道。
对于更通用的代码,您可以使用:function-traits 或来自 this answer 的代码。
或者使用std::array from begging 而不是std::list(很多通用模板代码,但编译时检查良好)

【讨论】:

    【解决方案2】:

    std::tuplestd::array 中的元素数量是其类型信息的一部分。因此,上面提出的函数args_as_tuple 必须以某种方式成为模板,并且结果的每个不同可能大小都需要对该模板进行不同的实例化。因此,除非该程序的代码是无限的(不可能),否则您无法制作可以支持任意多个元组大小的程序。

    如果您只关心 int 的值范围,例如,您可以将模板实例化 40 亿次,但您的可执行文件将至少有 4 GB 大。

    如果您真的只关心实际程序中几个不同大小的向量,您可以只实例化这些模板并编写转换代码,以解决std::list::size() 的值并调用适当的功能(乏味)。

    但你的确切代码 sn-p

    std::list<int> args_as_list = {1, 2, 3, 4};
    auto tpl = args_as_tuple(args_as_list);
    

    不能在 C++ 中永远工作。因为,在 C++ 中,所有变量都必须具有在编译时确定的已知类型。即使您使用关键字autoauto 也必须在编译时解析为固定类型,这意味着如果它是元组或数组,则它的大小是固定的,无论表达式args_as_tuple 是哪种模板恶作剧正在做。

    【讨论】:

      【解决方案3】:

      由于我的问题无法解决,我解决了一个稍微不同的问题,让我继续前进。

      我想出了一个解决方案,它允许我从容器中提取函子的参数。我可以用我想要评估的函子实例化 eval_container,然后将容器传递给结果对象。

      #include <utility>
      
      template <int N>
      using Int = std::integral_constant<int, N>;
      
      template <typename T>
      struct arity : arity<decltype(&T::operator())> {};
      
      template <typename T, typename RT, typename...Args>
      struct arity<RT(T::*)(Args...) const>
      {
          // could enforce maximum number of arguments
          static constexpr int value = sizeof...(Args);
      };
      
      template <typename F, int N = arity<F>::value>
      struct eval_container
      {
          eval_container(F const& f) : f(f) {}
          eval_container(F&& f) : f(std::move(f)) {}
      
          template <typename Iter, typename I, typename...Args>
          auto operator()(Iter&& iter, I, Args&&...args) const
          {
              // assert(iter != end)
              auto&& arg = *iter++;
              return (*this)(std::forward<Iter>(iter)
                           , Int<I()-1>{}
                           , std::forward<Args>(args)...
                           , arg);
          }
      
          template <typename Iter, typename...Args>
          auto operator()(Iter&&, Int<0>, Args&&...args) const
          {
              // assert(iter == end)
              return f(std::forward<Args>(args)...);
          }
      
          template <typename C>
          auto operator()(C const& container) const
          {
              return (*this)(container.begin(), Int<N>{});
          }
      
          F f;
      };
      

      }

      【讨论】:

        猜你喜欢
        • 2012-04-07
        • 1970-01-01
        • 1970-01-01
        • 2012-10-28
        • 2021-11-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-30
        相关资源
        最近更新 更多