Exemple
#include <iostream>
template <int N> struct Factorial
{
enum { val = Factorial<N-1>::val * N };
};
template<>
struct Factorial<0>
{
enum { val = 1 };
};
int main()
{
// Note this value is generated at compile time.
// Also note that most compilers have a limit on the depth of the recursion available.
std::cout << Factorial<4>::val << "\n";
}
C'était un peu amusant mais pas très pratique.
Pour répondre à la deuxième partie de la question:
ce fait est-il utile en pratique?
Réponse courte: en quelque sorte.
Réponse longue: Oui, mais uniquement si vous êtes un démon de modèle.
Faire une bonne programmation en utilisant une métaprogrammation modèle qui est vraiment utile pour d'autres (c'est-à-dire une bibliothèque) est vraiment très difficile (bien que faisable). Pour aider à booster a même MPL aka (Meta Programming Library). Mais essayez de déboguer une erreur de compilateur dans votre code de modèle et vous serez dans une longue course difficile.
Mais un bon exemple pratique d'utilisation pour quelque chose d'utile:
Scott Meyers a travaillé sur des extensions du langage C ++ (j'utilise le terme vaguement) en utilisant les fonctionnalités de création de modèles. Vous pouvez en savoir plus sur son travail ici ' Application des fonctionnalités du code '
J'ai fait une machine de turing en C ++ 11. Les fonctionnalités ajoutées par C ++ 11 ne sont en effet pas significatives pour la machine de turing. Il fournit simplement des listes de règles de longueur arbitraire utilisant des modèles variadiques, au lieu d'utiliser une métaprogrammation de macro perverse :). Les noms des conditions sont utilisés pour générer un diagramme sur stdout. J'ai supprimé ce code pour garder l'exemple court.
la source
" C ++ Templates Are Turing Complete " donne une implémentation d'une machine de Turing dans des templates ... ce qui n'est pas trivial et prouve le point d'une manière très directe. Bien sûr, ce n'est pas non plus très utile!
la source
Mon C ++ est un peu rouillé, donc peut-être pas parfait, mais c'est proche.
Le but est de démontrer que le compilateur évalue complètement la définition récursive jusqu'à ce qu'il atteigne une réponse.
la source
Pour donner un exemple non trivial: http://gitorious.org/metatrace , un traceur de rayons au moment de la compilation C ++.
Notez que C ++ 0x ajoutera une fonctionnalité non-modèle, au moment de la compilation et complète sous la forme de
constexpr
:Vous pouvez utiliser
constexpr
-expression partout où vous avez besoin de constantes de temps de compilation, mais vous pouvez également appelerconstexpr
-functions avec des paramètres non const.Une chose intéressante est que cela activera enfin les calculs en virgule flottante au moment de la compilation, bien que la norme stipule explicitement que les arithmétiques en virgule flottante au moment de la compilation n'ont pas à correspondre à l'arithmétique en virgule flottante à l'exécution:
la source
Le livre Modern C ++ Design - Generic Programming and Design Pattern par Andrei Alexandrescu est le meilleur endroit pour acquérir une expérience pratique avec des modèles de programmation génériques utiles et puissants.
la source
L'exemple factoriel ne montre pas en fait que les modèles sont complets de Turing, autant qu'il montre qu'ils prennent en charge la récursivité primitive. Le moyen le plus simple de montrer que les modèles sont complets est la thèse de Church-Turing, c'est-à-dire en implémentant soit une machine de Turing (désordonnée et un peu inutile), soit les trois règles (app, abs var) du calcul lambda non typé. Ce dernier est beaucoup plus simple et beaucoup plus intéressant.
Ce qui est discuté est une fonctionnalité extrêmement utile quand on comprend que les modèles C ++ permettent une programmation fonctionnelle pure à la compilation, un formalisme expressif, puissant et élégant mais aussi très compliqué à écrire si vous avez peu d'expérience. Notez également combien de personnes trouvent que le simple fait d'obtenir du code fortement modélisé peut souvent demander un gros effort: c'est exactement le cas des langages fonctionnels (purs), qui rendent la compilation plus difficile mais produisent étonnamment du code qui ne nécessite pas de débogage.
la source
Je pense que cela s'appelle la méta-programmation de modèle .
la source
Eh bien, voici une implémentation de Turing Machine au moment de la compilation exécutant un castor occupé à 4 états à 2 symboles
Preuve Ideone: https://ideone.com/MvBU3Z
Explication: http://victorkomarov.blogspot.ru/2016/03/compile-time-turing-machine.html
Github avec plus d'exemples: https://github.com/fnz/CTTM
la source
Vous pouvez consulter cet article du Dr Dobbs sur une implémentation FFT avec des modèles que je ne trouve pas si triviaux. Le point principal est de permettre au compilateur d'effectuer une meilleure optimisation que pour les implémentations sans modèle car l'algorithme FFT utilise beaucoup de constantes (tables sin par exemple)
partie I
deuxieme PARTIE
la source
Il est également amusant de souligner qu'il s'agit d'un langage purement fonctionnel, bien qu'il soit presque impossible à déboguer. Si vous regardez le message de James, vous verrez ce que je veux dire par être fonctionnel. En général, ce n'est pas la fonctionnalité la plus utile de C ++. Il n'a pas été conçu pour cela. C'est quelque chose qui a été découvert.
la source
Cela peut être utile si vous souhaitez calculer des constantes au moment de la compilation, du moins en théorie. Découvrez la métaprogrammation des modèles .
la source
Un exemple qui est raisonnablement utile est une classe de ratio. Il existe quelques variantes qui flottent. Attraper le cas D == 0 est assez simple avec des surcharges partielles. Le véritable calcul consiste à calculer le GCD de N et D et à compiler le temps. Ceci est essentiel lorsque vous utilisez ces ratios dans les calculs de compilation.
Exemple: lorsque vous calculez centimètres (5) * kilomètres (5), au moment de la compilation, vous multipliez le rapport <1,100> et le rapport <1000,1>. Pour éviter tout débordement, vous voulez un ratio <10,1> au lieu d'un ratio <1000,100>.
la source
Une machine de Turing est Turing-complète, mais cela ne signifie pas que vous devriez en utiliser une pour le code de production.
Essayer de faire quelque chose de non trivial avec des modèles est selon mon expérience désordonné, laid et inutile. Vous n'avez aucun moyen de "déboguer" votre "code", les messages d'erreur lors de la compilation seront cryptiques et généralement dans les endroits les plus improbables, et vous pouvez obtenir les mêmes avantages de performances de différentes manières. (Indice: 4! = 24). Pire encore, votre code est incompréhensible pour le programmeur C ++ moyen, et ne sera probablement pas portable en raison du large éventail de niveaux de support dans les compilateurs actuels.
Les modèles sont parfaits pour la génération de code générique (classes de conteneurs, wrappers de classe, mix-ins), mais non - à mon avis, l'exhaustivité des modèles de Turing n'est PAS UTILE en pratique.
la source
Juste un autre exemple de comment ne pas programmer:
Les modèles de publication sur C ++ sont terminés
la source
K17<Depth+1>::x * 5
.