Przykład
#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";
}
To było trochę zabawne, ale niezbyt praktyczne.
Odpowiadając na drugą część pytania:
czy ten fakt jest przydatny w praktyce?
Krótka odpowiedź: w pewnym sensie.
Długa odpowiedź: tak, ale tylko jeśli jesteś demonem szablonów.
Okazanie dobrego programowania przy użyciu metaprogramowania szablonowego, które jest naprawdę przydatne dla innych (np. Biblioteki), jest naprawdę trudne (choć wykonalne). Aby pomóc zwiększyć, ma nawet MPL aka (biblioteka programowania meta). Ale spróbuj zdebugować błąd kompilatora w kodzie szablonu, a czeka Cię długa, ciężka jazda.
Ale dobry praktyczny przykład wykorzystania go do czegoś pożytecznego:
Scott Meyers pracował nad rozszerzeniami języka C ++ (używam tego terminu luźno) przy użyciu narzędzi do tworzenia szablonów. Możesz przeczytać o jego pracy tutaj „ Egzekwowanie funkcji kodu ”
Zrobiłem maszynę Turinga w C ++ 11. Funkcje, które dodaje C ++ 11, nie są faktycznie istotne dla maszyny Turinga. Po prostu zapewnia listy reguł o dowolnej długości przy użyciu szablonów wariadycznych, zamiast używania przewrotnego metaprogramowania makr :). Nazwy warunków są używane do wyświetlania diagramu na standardowe wyjście. Usunąłem ten kod, aby próbka była krótka.
źródło
„ C ++ Templates Are Turing Complete ” to implementacja maszyny Turinga w szablonach ... co jest nietrywialne i udowadnia to w bardzo bezpośredni sposób. Oczywiście nie jest to również zbyt przydatne!
źródło
Mój C ++ jest trochę zardzewiały, więc może nie być idealny, ale jest blisko.
Chodzi o to, aby wykazać, że kompilator całkowicie ocenia definicję rekurencyjną, dopóki nie osiągnie odpowiedzi.
źródło
Aby dać nietrywialny przykład: http://gitorious.org/metatrace , kompilator C ++ ray tracer czasu.
Zauważ, że C ++ 0x doda nie-szablonowy, kompletny w czasie kompilacji, kompletny obiekt w postaci
constexpr
:Możesz użyć
constexpr
-expression wszędzie tam, gdzie potrzebujesz stałych czasu kompilacji, ale możesz również wywołaćconstexpr
-functions z parametrami innymi niż const.Jedną fajną rzeczą jest to, że w końcu umożliwi to obliczenie zmiennoprzecinkowej kompilacji czasu, chociaż standard wyraźnie stwierdza, że arytmetyka zmiennoprzecinkowa kompilacji czasu nie musi pasować do arytmetyki zmiennoprzecinkowej czasu działania:
źródło
Książka Modern C ++ Design - Generic Programming and Design Pattern autorstwa Andrei Alexandrescu to najlepsze miejsce na zdobycie praktycznych doświadczeń z użytecznymi i potężnymi wzorcami programowania ogólnego.
źródło
Przykład silni w rzeczywistości nie pokazuje, że szablony są kompletne w Turingu, ale pokazuje, że obsługują rekursję pierwotną. Najłatwiejszym sposobem wykazania, że szablony są kompletne, jest teza Church-Turinga, czyli zaimplementowanie maszyny Turinga (niechlujnej i trochę bezcelowej) lub trzech reguł (app, abs var) nietypowego rachunku lambda. To drugie jest dużo prostsze i dużo ciekawsze.
To, co jest omawiane, jest niezwykle przydatną funkcją, gdy zrozumiesz, że szablony C ++ umożliwiają czyste programowanie funkcjonalne w czasie kompilacji, formalizm, który jest ekspresyjny, potężny i elegancki, ale także bardzo skomplikowany do napisania, jeśli masz niewielkie doświadczenie. Zwróć także uwagę, jak wiele osób uważa, że samo uzyskanie kodu opartego na szablonach często wymaga dużego wysiłku: tak właśnie jest w przypadku (czystych) języków funkcjonalnych, które sprawiają, że kompilowanie jest trudniejsze, ale zaskakująco daje kod, który nie wymaga debugowania.
źródło
Myślę, że nazywa się to metaprogramowaniem szablonów .
źródło
Cóż, oto implementacja Turing Machine w czasie kompilacji, działająca na 4-stanowym, zajętym bobrze z 2 symbolami
Testowy test Ideone: https://ideone.com/MvBU3Z
Wyjaśnienie: http://victorkomarov.blogspot.ru/2016/03/compile-time-turing-machine.html
Github z dodatkowymi przykładami: https://github.com/fnz/CTTM
źródło
Możesz sprawdzić ten artykuł dr. Dobbsa na temat implementacji FFT z szablonami, które nie są moim zdaniem takie trywialne. Głównym celem jest umożliwienie kompilatorowi wykonania lepszej optymalizacji niż w przypadku implementacji innych niż szablony, ponieważ algorytm FFT wykorzystuje wiele stałych (na przykład tabele sin)
część I
część druga
źródło
Fajnie jest również wskazać, że jest to język czysto funkcjonalny, chociaż prawie niemożliwy do debugowania. Jeśli spojrzysz na post Jamesa , zobaczysz, co mam na myśli, mówiąc, że jest funkcjonalny. Ogólnie nie jest to najbardziej użyteczna funkcja C ++. Nie został do tego przeznaczony. To coś, co zostało odkryte.
źródło
Może to być przydatne, jeśli chcesz obliczyć stałe w czasie kompilacji, przynajmniej w teorii. Sprawdź metaprogramowanie szablonów .
źródło
Przykładem, który jest dość użyteczny, jest klasa współczynników. Istnieje kilka wariantów. Wyłapywanie przypadku D == 0 jest dość proste w przypadku częściowych przeciążeń. Prawdziwe obliczenie polega na obliczaniu GCD N i D oraz czasu kompilacji. Jest to niezbędne, gdy używasz tych współczynników w obliczeniach w czasie kompilacji.
Przykład: podczas obliczania centymetrów (5) * kilometrów (5) w czasie kompilacji pomnożymy współczynnik <1,100> i współczynnik <1000,1>. Aby zapobiec przepełnieniu, potrzebujesz współczynnika <10,1> zamiast współczynnika <1000,100>.
źródło
Maszyna Turinga jest Turing-complete, ale to nie znaczy, że chcesz użyć jednego kodu produkcyjnego.
Z mojego doświadczenia wynika, że próba zrobienia czegoś nietrywialnego za pomocą szablonów jest niechlujna, brzydka i bezcelowa. Nie masz możliwości "debugowania" swojego "kodu", komunikaty o błędach kompilacji będą niejasne i zwykle w najbardziej nieprawdopodobnych miejscach, a te same korzyści w zakresie wydajności można osiągnąć na różne sposoby. (Podpowiedź: 4! = 24). Co gorsza, Twój kod jest niezrozumiały dla przeciętnego programisty C ++ i prawdopodobnie będzie nieprzenośny ze względu na szeroki zakres wsparcia w obecnych kompilatorach.
Szablony świetnie nadają się do generowania kodu ogólnego (klasy kontenerów, opakowania klas, mix-iny), ale nie - moim zdaniem kompletność szablonów Turinga NIE JEST PRZYDATNA w praktyce.
źródło
Kolejny przykład, jak nie programować:
Publikowanie szablonów w C ++ jest w toku
źródło
K17<Depth+1>::x * 5
.