バックグラウンド
次の点を考慮してください。
template <unsigned N>
struct Fibonacci
{
enum
{
value = Fibonacci<N-1>::value + Fibonacci<N-2>::value
};
};
template <>
struct Fibonacci<1>
{
enum
{
value = 1
};
};
template <>
struct Fibonacci<0>
{
enum
{
value = 0
};
};
これは一般的な例で、フィボナッチ数の値をコンパイル時の定数として取得できます。
int main(void)
{
std::cout << "Fibonacci(15) = ";
std::cout << Fibonacci<15>::value;
std::cout << std::endl;
}
しかし、明らかに実行時に値を取得することはできません:
int main(void)
{
std::srand(static_cast<unsigned>(std::time(0)));
// ensure the table exists up to a certain size
// (even though the rest of the code won't work)
static const unsigned fibbMax = 20;
Fibonacci<fibbMax>::value;
// get index into sequence
unsigned fibb = std::rand() % fibbMax;
std::cout << "Fibonacci(" << fibb << ") = ";
std::cout << Fibonacci<fibb>::value;
std::cout << std::endl;
}
fibbはコンパイル時の定数ではないためです。
質問
だから私の質問は:
実行時にこのテーブルを覗く最良の方法は何ですか? 最も明白な解決策 (「解決策」は軽視する必要があります) は、大きな switch ステートメントを使用することです。
unsigned fibonacci(unsigned index)
{
switch (index)
{
case 0:
return Fibonacci<0>::value;
case 1:
return Fibonacci<1>::value;
case 2:
return Fibonacci<2>::value;
.
.
.
case 20:
return Fibonacci<20>::value;
default:
return fibonacci(index - 1) + fibonacci(index - 2);
}
}
int main(void)
{
std::srand(static_cast<unsigned>(std::time(0)));
static const unsigned fibbMax = 20;
// get index into sequence
unsigned fibb = std::rand() % fibbMax;
std::cout << "Fibonacci(" << fibb << ") = ";
std::cout << fibonacci(fibb);
std::cout << std::endl;
}
しかし、現在、テーブルのサイズは非常にハードコードされており、40 まで拡張するのは容易ではありません。
私が思いついたのは、同様のクエリ方法を持つ唯一のものです。
template <int TableSize = 40>
class FibonacciTable
{
public:
enum
{
max = TableSize
};
static unsigned get(unsigned index)
{
if (index == TableSize)
{
return Fibonacci<TableSize>::value;
}
else
{
// too far, pass downwards
return FibonacciTable<TableSize - 1>::get(index);
}
}
};
template <>
class FibonacciTable<0>
{
public:
enum
{
max = 0
};
static unsigned get(unsigned)
{
// doesn't matter, no where else to go.
// must be 0, or the original value was
// not in table
return 0;
}
};
int main(void)
{
std::srand(static_cast<unsigned>(std::time(0)));
// get index into sequence
unsigned fibb = std::rand() % FibonacciTable<>::max;
std::cout << "Fibonacci(" << fibb << ") = ";
std::cout << FibonacciTable<>::get(fibb);
std::cout << std::endl;
}
これはうまくいくようです。私が見る唯一の問題は次の2つです。
Fibonacci<2> を計算するには、TableMax を 2 まで通過する必要があるため、コール スタックが大きくなる可能性があります。
値がテーブルの外にある場合は、計算ではなくゼロを返します。
それで、私が見逃しているものはありますか?実行時にこれらの値を選択するより良い方法があるはずです。
おそらく、switch ステートメントのテンプレート メタプログラミング バージョンで、switch ステートメントを特定の数まで生成しますか?
前もって感謝します。