Arrière-plan
Considérez les points suivants:
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
};
};
Il s'agit d'un exemple qui nous permet d'obtenir la valeur d'un nombre de Fibonacci comme une constante de compilation:
int main(void)
{
std::cout << "Fibonacci(15) = ";
std::cout << Fibonacci<15>::value;
std::cout << std::endl;
}
Mais de toute évidence vous ne peut pas obtenir la valeur au moment de l'exécution:
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;
}
Parce que fibb n'est pas une constante de compilation.
Question
Donc ma question est:
Quel est le meilleur moyen pour avoir un aperçu de ce tableau au moment de l'exécution? La solution la plus évidente (et la "solution" doit être prise à la légère), est d'avoir une grande instruction 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;
}
Mais maintenant, la taille de la table est très codée en dur et il ne serait pas facile de l'étendre à-dire, 40.
Le seul que j'ai trouvé qui a une semblable méthode de requête est ceci:
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;
}
Qui semble fonctionner à merveille. Les deux seuls problèmes que je rencontre sont:
Potentiellement grande pile d'appel, puisque le calcul de Fibonacci<2> nécessite que l'on en passer par TableMax tout le chemin à 2, et:
Si la valeur est en dehors de la table, elle renvoie zéro plutôt que de calculer.
Donc, il y a quelque chose que je suis absent? Il semble qu'il devrait y avoir une meilleure façon de choisir ces valeurs lors de l'exécution.
Un modèle de la métaprogrammation version d'une instruction switch peut-être, qui génère une instruction switch jusqu'à un certain nombre?
Merci à l'avance.