所以,假设我有一个模板结构 - 函数fib<i>::value
。我想在运行时获得第n个斐波纳契数。为此,我创建数组fibs[] = { fib<0>::value, ... , fib<maxN>::value }
。不幸的是,对于某些函数maxN
可能非常大,我不能只用手填充它。因此,我编写了一些预处理程序指令,以使任务更容易。
#define fib(x) (fib<(x)>::value)
#define fibLine_level_0(x) fib(5*(x) + 0), fib(5*(x) + 1), fib(5*(x) + 2), fib(5*(x) + 3), fib(5*(x) + 4)
#define fibLine_level_1(x) fibLine_level_0(2*(x) + 0), fibLine_level_0(2*(x) + 1)
#define fibLine_level_2(x) fibLine_level_1(2*(x) + 0), fibLine_level_1(2*(x) + 1)
#define fibLine_level_3(x) fibLine_level_2(2*(x) + 0), fibLine_level_2(2*(x) + 1)
#define cAarrSize(x) (sizeof(x) / sizeof(x[0]))
我这样使用它:
int fibs[] = { fibLine_level_3(0) };
for (int i = 0; i < cAarrSize(fibs); i++)
cout << "fib(" << i << ") = " << fibs[i] << endl;
您可能需要的代码:
template<int i>
struct fibPair{
static const int fst = fibPair<i-1>::snd;
static const int snd = fibPair<i-1>::fst + fibPair<i-1>::snd;
};
template<>
struct fibPair<0> {
static const int fst = 0;
static const int snd = 1;
};
template<int i>
struct fib {
static const int value = fibPair<i>::fst;
};
但这段代码真的很难看。怎么做才能让它变得更漂亮?
约束:此代码必须用于运动编程。这意味着 - 没有第三方库,有时没有C ++ 11(但它可以)
答案 0 :(得分:3)
Fib
结构可以重写如下:
template <size_t i>
struct fib
{
static const size_t value = fib<i - 1>::value + fib<i - 2>::value;
};
template <>
struct fib<0>
{
static const size_t value = 0;
};
template <>
struct fib<1>
{
static const size_t value = 1;
};
可以使用C ++ 11计算Fibonacci数的编译时数组。
修改1 (更改了fib
值的类型)。
编辑2 :
Fibonacci数字数组的编译时生成(基于this答案)。
template<unsigned... args> struct ArrayHolder
{
static const unsigned data[sizeof...(args)];
};
template<unsigned... args>
const unsigned ArrayHolder<args...>::data[sizeof...(args)] = { args... };
template<size_t N, template<size_t> class F, unsigned... args>
struct generate_array_impl
{
typedef typename generate_array_impl<N-1, F, F<N>::value, args...>::result result;
};
template<template<size_t> class F, unsigned... args>
struct generate_array_impl<0, F, args...>
{
typedef ArrayHolder<F<0>::value, args...> result;
};
template<size_t N, template<size_t> class F>
struct generate_array
{
typedef typename generate_array_impl<N-1, F>::result result;
};
int main()
{
const size_t count = 10;
typedef generate_array<count, fib>::result fibs;
for(size_t i = 0; i < count; ++i)
std::cout << fibs::data[i] << std::endl;
}
您只需要为generate_array
提供生成«功能»(我们的fib
结构)。
答案 1 :(得分:0)
感谢@nameless,提供问题的链接,我在@MichaelAnderson找到了answer的简单c ++(没有新功能)。我使用它并根据自己的需要进行扩展。
所以,概念很简单,但有点奇怪。我们必须产生递归模板结构,其中第一个字段是与其他参数相同的模板结构。
template<size_t N>
struct FibList {
FibList<N-1> previous;
size_t value;
FibList<N>() : value(fib<N>::value) {}
};
让我们尝试扩展一下(只是为了看看,编译器会产生什么):
template<size_t N>
struct FibList {
FibList<N-3> previous;
size_t value_N_minus_2;
size_t value_N_minus_1;
size_t value_N;
};
所以我们可以认为FibList是数组并且只是投射它(这是我的解决方案的弱点 - 我现在无法证明这一点)
static const size_t maxN = 2000;
FibList<maxN> fibList;
size_t *fibArray = &fibList.value - maxN;
或以另一种方式:
size_t *fibArray = reinterpret_cast<size_t*>(&fibList);
重要:数组的大小为maxN + 1,但获取数组大小(sizeof(array) / sizeof(array[0]
)的标准方法将失败。对此非常准确。
现在我们必须停止递归:
// start point
template<>
struct FibList<0> {
size_t value;
FibList<0>() : value(0) {}
};
// start point
template<>
struct FibList<1> {
FibList<0> previous;
size_t value;
FibList<1>() : value(1) {}
};
注意,交换FibList<1>
和FibList<0>
的位置会在编译器中产生堆栈溢出。
我们必须解决另一个问题 - 模板递归的深度有限(取决于编译器和/或选项)。但是,幸运的是,编译器只有深度限制,而不是模板的内存限制(好吧,是的,内存限制比深度限制更大)。因此,我们有明显丑陋的解决方案 - 串联调用fib<N>
,步长等于深度限制 - 我们永远不会捕获关于fib<N>
的模板深度限制。但我们不能在运行时写fib<500>::value
。所以我们得到了解决方案 - 使用FibList<N>
专门编写fib<N>::value
的宏:
#define SetOptimizePointForFib(N) template<>\
struct FibList<N> {\
FibList<(N)-1> previous;\
size_t value;\
FibList<N>() : value(fib<N>::value) {}\
};
我们必须写下这样的东西:
SetOptimizePointForFib(500);
SetOptimizePointForFib(1000);
SetOptimizePointForFib(1500);
SetOptimizePointForFib(2300);
所以我们确实编译了时间prealc并填充了很棒的静态数组。