简体   繁体   English

如何仅使用参数包在C ++ 11中实现boost MPL FOLD?

[英]How to implement boost MPL FOLD in C++11 only using parameter pack ?

boost mpl has more common algo - fold . 升压MPL有更多共同的算法中- This algo is basic for many other algorithms. 该算法是许多其他算法的基础。

template< typename Seq, typename State, typename Op> struct fold { ... }
//Here Seq is <T0,T1,...,Tn> any sequence.
// result of fold is  op<  op < ...< op<State,T0>::type, T1>::type > ... >, Tn>::type

for more information read link . 有关更多信息,请阅读链接

Fold in c++11 with variadic templates may redefined following: 在c ++ 11中使用可变参数模板Fold可以重新定义以下内容:

 template< typename state, typename op, typename ...elements> struct fold;

How to implement it is not problem, but HOW TO IMPLEMENT IT using only parameter packing is difficult or may unsolveable problem. 如何实现它不是问题,但是如何仅使用参数打包来实现它却很困难或可能无法解决。

Q: Can it to implement only using parameter packing?? 问:能否仅使用参数打包来实现?

I want something like 我想要类似的东西

template< typename OP, typename State, typename ...T>
struct fold
{
     // only for illustration
     typedef  apply< apply<....<apply<Op,State,T>>...>::type type; 
};

Here is a stab at a logarithmic template recursion depth fold implementation. 这是对数模板递归深度fold实现的一个突破。

#include <cstddef>

template<typename... Ts> struct types {};
template<typename T, typename U>
struct concat;
template<typename... Ts, typename... Us>
struct concat< types<Ts...>, types<Us...> > {
  typedef types<Ts..., Us...> result;
};
template<typename Ts, typename Us>
using Concat = typename concat<Ts, Us>::result;

template<std::size_t n, typename Ts>
struct split;
template<std::size_t n, typename... Ts>
struct split<n, types<Ts...>> {
private:
  typedef split<n/2, types<Ts...>> one;
  typedef split<n-n/2, typename one::right> two;
public:
  typedef Concat< typename one::left, typename two::left > left;
  typedef typename two::right right;
};
template<typename... Ts>
struct split<0, types<Ts...>> {
  typedef types<> left;
  typedef types<Ts...> right;
};
template<typename T, typename... Ts>
struct split<1, types<T, Ts...>> {
  typedef types<T> left;
  typedef types<Ts...> right;
};
template<template<typename, typename>class OP, typename State, typename Ts>
struct fold_helper;
template<template<typename, typename>class OP, typename State, typename... Ts>
struct fold_helper<OP, State, types<Ts...>> {
private:
  typedef split<sizeof...(Ts)/2, types<Ts...>> parts;
  typedef typename parts::left left;
  typedef typename parts::right right;
  typedef typename fold_helper<OP, State, left>::result left_result;
public:
  typedef typename fold_helper<OP, left_result, right>::result result;
};
template<template<typename, typename>class OP, typename State>
struct fold_helper<OP, State, types<>> {
  typedef State result;
};
template<template<typename, typename>class OP, typename State, typename T>
struct fold_helper<OP, State, types<T>> {
  typedef typename OP<State,T>::type result;
};
template<template<typename, typename>class OP, typename State, typename... Ts>
struct fold {
  typedef typename fold_helper<OP, State, types<Ts...>>::result type;
};
template<template<typename, typename>class OP, typename State, typename... Ts>
using Fold = typename fold<OP, State, Ts...>::type;

template<typename left, typename right>
struct op_test {
  typedef int type;
};

int main() {
  Fold< op_test, double, int, char, char*, int* > foo = 8;
}

here I first take the linear list, and break it into two half-length lists using the split metafunction. 在这里,我首先获取线性列表,然后使用split元函数将其分成两个半长列表。

Once I have two halves, I fold over the first half, then take the result of that and fold over the second half. 当我有两半时,我将上半部分对fold ,然后取其结果再对下半部分对fold

While O(N) work is done, you are only O(lg(N)) deep at any point. 完成O(N)工作后,您在任何时候都只有O(lg(N))深。

I don't see a theoretical reason why we cannot pull off O(lg(lg(N)) depth, but neither do I see the point: with a ~1000 max depth, you'd have to have dozens of nested fold s on type lists 100s long to run out of template stack space: in my experience the compiler blows up long before the logarithmic depth limit is reached. 我看不到理论上的原因,为什么我们无法提取O(lg(lg(lg(N)))的深度,但我也看不到这一点:最大深度为〜1000时,您必须有数十个嵌套的fold s在类型列表上,要用100秒钟的时间来耗尽模板堆栈空间:以我的经验,编译器在达到对数深度限制之前就炸毁了。

And now it compiles: http://ideone.com/CdKAAT 现在它可以编译: http : //ideone.com/CdKAAT

split is a generally useful way of dealing with long lists without recursing once per element. split是处理长列表而不对每个元素重复一次的一种通常有用的方法。 fold and fold_helper are pretty obvious once you have the logarithmic split . 一旦进行对数split foldfold_helper就很明显了。

Why the restriction on only parameter packing? 为什么只限制参数包装?

Like many parameter pack solutions, you're likely going to have to delve into either some sort of overloading or partial specialization. 像许多参数包解决方案一样,您可能必须研究某种重载或部分专业化知识。 Given that you're writing a template metafunction, I would go with partial specialization. 鉴于您正在编写模板元函数,因此我将进行部分专门化。

The below handles the case with 0 elements by returning state, and we use that position in the template to accumulate the result. 下面通过返回状态来处理具有0个元素的情况,我们使用模板中的该位置来累加结果。 The specialization handles the 1+ case, by combining the first element with the state, and recursively calling the template metafunction. 通过将第一个元素与状态组合,然后递归调用模板元函数,专业化处理1+情况。

template< typename OP, typename State, typename ...T>
struct fold
{
    typedef State type;
};

template<typename OP, typename State, typename Head, typename... Tail>
struct fold< OP, State, Head, Tail...>
{
   typedef typename fold<OP, typename OP::template apply<State,Head>::type, Tail...>::type type;
};

http://ideone.com/DDCCbB http://ideone.com/DDCCbB

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM