C 11:具有对数评估深度的编译时间阵列

C++11: Compile-time Array with Logarithmic Evaluation Depth

本文关键字:深度 编译 时间 阵列 评估      更新时间:2023-10-16

实现C 11数组的一种方法,该数组的元素是由编译器计算出的索引的函数初始化的,并将结果存储在数据部分(.rodata)中应用程序图像是使用模板,部分专业化和constexPR如下:

#include <iostream>
#include <array>
using namespace std;
constexpr int N = 1000000;
constexpr int f(int x) { return x*2; }
typedef array<int, N> A;
template<int... i> constexpr A fs() { return A{{ f(i)... }}; }
template<int...> struct S;
template<int... i> struct S<0,i...>
{ static constexpr A gs() { return fs<0,i...>(); } };
template<int i, int... j> struct S<i,j...>
{ static constexpr A gs() { return S<i-1,i,j...>::gs(); } };
constexpr auto X = S<N-1>::gs();
int main()
{
        cout << X[3] << endl;
}

这对n:

的大值不起作用
error: constexpr evaluation depth exceeds maximum of 512 

这是由于递归模板评估的头尾风格,其在n。

方面具有线性深度

有没有办法这样做,以使评估深度在n而不是线性方面是对数?(因此将避免默认深度极限)

如果您在代码中使用的内容是索引技巧的怪异形式,则是具有O(log N)实例的实现:

// using aliases for cleaner syntax
template<class T> using Invoke = typename T::type;
template<unsigned...> struct seq{ using type = seq; };
template<class S1, class S2> struct concat;
template<unsigned... I1, unsigned... I2>
struct concat<seq<I1...>, seq<I2...>>
  : seq<I1..., (sizeof...(I1)+I2)...>{};
template<class S1, class S2>
using Concat = Invoke<concat<S1, S2>>;
template<unsigned N> struct gen_seq;
template<unsigned N> using GenSeq = Invoke<gen_seq<N>>;
template<unsigned N>
struct gen_seq : Concat<GenSeq<N/2>, GenSeq<N - N/2>>{};
template<> struct gen_seq<0> : seq<>{};
template<> struct gen_seq<1> : seq<0>{};
// example
template<unsigned... Is>
void f(seq<Is...>);
int main(){
  f(gen_seq<6>());
}

实时示例。

在带有常规constexpression函数的C 14中不需要任何序列,make_sequence

static constexpr int f(int i) noexcept { return i * 2; }
template< int N, typename F >
static constexpr std::array<int,N> generate_array( F fo ) noexcept
{
     std::array< int, N > result{}; // init with zero
     int i = 0; 
     for( auto& x : result) x = fo(++i);
     return result;
}
// test
constexpr auto arr = generate_array<10>( f );

只有一个问题,没有编译器可以编译它:)

唯一导致线性模板实例深度的唯一的尾递归模板是在S的模板参数列表中构造整数列表。

正如您所建议的那样,这可以在对数实例化深度中完成:

template <int ... Ints> struct seq;
template <int Start, int End> 
struct range
{
  typedef concat_seq<range<Start, Start+(End-Start)/2>::type, range<Start+(End-Start)/2, End>::type>::type type;
};
template<int Singleton>
struct range<Singleton, Singleton+1>
{
  typedef seq<Singleton> type;
};
template <int NoSingleton>
struct range<NoSinleton, NoSingleton>
{
  typedef seq<> type;
};

在适当的地方添加一堆typename S,实现concat_seq(易于),从range<0, N>::type提取fs的参数列表,然后您去。