计算模板递归嵌套深度

时间:2015-05-23 09:30:03

标签: c++ templates c++11 recursion sfinae

以下序列适用于对特定操作进行递归的递归 嵌套在数据并行容器中的嵌套模板对象中的嵌套级别 类。我提出了一个表达模板引擎,我尽可能地使用它 例如,想要转置一个多维容器的索引 阵列。

我相信SFINAE下的代码是明确的;

容器转到第三次出现的功能,无法匹配" NestLevel"。 "递归"通过第二次出现的函数进行递归,直到Nest Level匹配,并且递归在第一次出现函数时终止。

#include <vector>
#include <complex>
#include <type_traits>
#include <iostream>

typedef std::complex<double> ComplexD;

template <class T> class TypeMapper {
public:
  enum { NestLevel = T::NestLevel };
};

template<> class TypeMapper<ComplexD> {
public:
  enum { NestLevel = 0 };
};

template<class obj> class Container {
 public:
  std::vector<obj> data;
  Container(int size) : data (size){};
};

template<class obj> class Recursive {
public:
  enum { NestLevel = TypeMapper<obj>::NestLevel + 1};
  obj internal;
};

template<int N,class obj,typename std::enable_if<N==obj::NestLevel >::type * = nullptr > auto function(const obj &arg)-> obj
{
  std::cout<<"Leaf "<<obj::NestLevel<<std::endl;
  return arg;
}
template<int N,class obj,typename std::enable_if<N!=obj::NestLevel >::type * = nullptr > auto function(const obj &arg)-> obj
{
  std::cout<<"Node "<<obj::NestLevel<<std::endl;
  obj ret;
  ret.internal=function<N>(arg.internal);
  return ret;
}

template<int N,class obj> auto function(const Container<obj> & arg)-> Container<decltype(function<N>(arg.data[0]))>
{
  Container<decltype(function<N>(arg.data[0]))> ret(arg.data.size());
  for(int ss=0;ss<arg.data.size();ss++){
    ret.data[ss] = function<N>(arg.data[ss]);
  }
  return ret;
}


int main(int argc,char **argv)
{
  Container<Recursive<Recursive<ComplexD> > > array(10);
  Container<Recursive<Recursive<ComplexD> > > ret(10);

  ret = function<1>(array);
}

适用于Intel 15,Clang ++多个版本,可提供我期望的功能。

pab$ icpc -std=c++11 broken.cc -o broken
pab$ clang++  -std=c++11 broken.cc -o broken
pab$ clang++ --version
Apple LLVM version 6.0 (clang-600.0.56) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin14.1.0
Thread model: posix

pab$ icpc --version
icpc (ICC) 15.0.3 20150408
Copyright (C) 1985-2015 Intel Corporation.  All rights reserved.

我希望输出:

pab$ ./broken 
Node 2
Leaf 1
Node 2
Leaf 1
Node 2
Leaf 1
Node 2
Leaf 1
Node 2
Leaf 1
Node 2
Leaf 1
Node 2
Leaf 1
Node 2
Leaf 1
Node 2
Leaf 1
Node 2
Leaf 1

然后

function(const Container<obj> & arg) 

循环容器,调用

std::enable_if<N!=obj::NestLevel > function

这会递归,递减嵌套级别枚举,然后匹配

std::enable_if<N==obj::NestLevel > function.

但是,GCC无法解析此问题,而是在无限递归循环(4.8,4.9)中使用函数(Container)自调用并且内部编译器错误 在5.0。

pab$ g++-5 -std=c++11 broken.cc -o broken
'
Internal compiler error: Error reporting routines re-entered.

broken.cc: In substitution of 'template<int N, class obj> Container<decltype (function<N>(arg.data[0]))> function(const Container<obj>&) [with int N = 1; obj = <missing>]':
broken.cc:43:101:   recursively required by substitution of 'template<int N, class obj> Container<decltype (function<N>(arg.data[0]))> function(const Container<obj>&) [with int N = 1; obj = <missing>]'
broken.cc:43:101:   required by substitution of 'template<int N, class obj> Container<decltype (function<N>(arg.data[0]))> function(const Container<obj>&) [with int N = 1; obj = <missing>]'
broken.cc:45:33:   Abort trap: 6
 template<int N,class obj> auto function(const Container<obj> & arg)-> Container<decltype(function<N>(arg.data[0]))>
                                                                                                     ^
g++-5: internal compiler error: Abort trap: 6 (program cc1plus)
Please submit a full bug report,
with preprocessed source if appropriate.
See <https://github.com/Homebrew/homebrew-versions/issues> for instructions.`enter code here`

匹配看起来很麻烦,因为函数(const Container&amp; arg)不应该 因为参数不匹配而自行递归。应该改为 替换失败并调用另一个模板的功能。如果我重命名 这些并更改它编译的Container参数函数内的调用。

模板很难 - 我的程序是否合法,这是编译器错误?

更新:

#include <vector>
#include <complex>
#include <type_traits>
#include <iostream>

typedef std::complex<double> ComplexD;

template <class T> class TypeMapper {
public:
  enum { NestLevel = T::NestLevel };
};

template<> class TypeMapper<ComplexD> {
public:
  enum { NestLevel = 0 };
};

template<class obj> class Container {
 public:
  std::vector<obj> data;
  Container(int size) : data (size){};
};

template<class obj> class Recursive {
public:
  enum { NestLevel = TypeMapper<obj>::NestLevel + 1};
  obj internal;
};

template<int N,class obj,typename std::enable_if<N==obj::NestLevel >::type * = nullptr > auto function(const obj &arg)-> obj
{
  std::cout<<"Leaf "<<obj::NestLevel<<std::endl;
  return arg;
}
template<int N,class obj,typename std::enable_if<N!=obj::NestLevel >::type * = nullptr > auto function(const obj &arg)-> obj
{
  std::cout<<"Node "<<obj::NestLevel<<std::endl;
  obj ret;
  ret.internal=function<N>(arg.internal);
  return ret;
}

template<int N,class obj> auto ffunction(const Container<obj> & arg)-> Container<decltype(function<N>(arg.data[0]))>
{
  Container<decltype(function<N>(arg.data[0]))> ret(arg.data.size());
  for(int ss=0;ss<arg.data.size();ss++){
    ret.data[ss] = function<N>(arg.data[ss]);
  }
  return ret;
}


int main(int argc,char **argv)
{
  Container<Recursive<Recursive<ComplexD> > > array(10);
  Container<Recursive<Recursive<ComplexD> > > ret(10);

  ret = ffunction<1>(array);
}

这个重命名&#34;功能&#34;到&#34; ffunction&#34;消除前两次出现的第三次消歧,然后G ++产生正确的输出,因为它没有(错误地)递归到函数(容器)中。

似乎会影响所有版本的g ++。

0 个答案:

没有答案