Rozbalování smyček
Následující výraz
for (i = 0; i < n; i++) { data[i] = a[i]; }
lze zaměnit za
for (i = 0; i < n; i += k) { data[i] = a[i]; data[i+1] = a[i+1]; data[i+2] = a[i+2]; ... data[i+k-1] = a[i+k-1]; }
a tak umožnit lepší využití pipeline procesoru.
Specializace šablon
Zde vidíme použití specializace na výpočet fibonacciho čísla v době překladu. Prvně je definována obecná šablona, která obsahuje rekurzivní vzorec a následně jsou definovány specializace pro počáteční podmínky. Všechny propočty jsou realizovány v době kompilace a ve výsledném programu už najdeme jen číslo, které se vypisuje.
template<int N> struct fib { static const int result = fib<N-1>::result + fib<N-2>::result; }; template<> struct fib<0> { static const int result = 0; }; template<> struct fib<1> { static const int result = 1; };
#include <iostream> int main(int ac, char *av[]) { std::cout << "Fib(10) = " << fib<10>::result << std::endl; return 0; }
Specializace šablon s více parametry
template<arg(0), arg(1), ... arg(n)> class sablona { //defaultní chování }; template<arg(i0), arg(i1), ... arg(im)> class sablona< /* dosazení za parametry obecné šablony */ > { //specializace };
Obecná šablona má n
parametrů. Častečná specializace šablony má pro parametry s indexy {1..n} \ (i)1..m určené typy nebo přímo číselné hodnoty. Ostatní nespecifikované parametry šablony (i)1..m je třeba uvést jako parametry specializace za klíčové slovo template
. Častečná specializace šablony tedy má méně parametrů než obecná šablona a za názvem třídy se uvádí nespecifikované parametry a hodnoty parametrů, pro kterou šablonu specializujeme.
Šablona pro rozbalení smyčky
Tato šablona má dva parametry: počet řádek, které je potřeba rozbalit a výraz, na kterém se provádí. Rekurzivně se volá tak dlouho, až dojde k rozbalení posledního výrazu. Celý cyklus je ukončen specializací šablony.
template <int loops, class A> class loop_unroll { public: static const int n = loops; inline static void do_loops(double data[], const A &a, int i) { //tato řádka se rozbalí data[i] = a[i]; //využití šablony o 1 menší loop_unroll<n-1, A>::do_loops(data, a, i+1); } }; /* specializace šablony pro 0 opakování */ template <class A> class loop_unroll<0, A> { public: inline static void do_loops(double data[], const A a, int i) {} }; //--------------------------použití------------------------------------------- template <class A> void operator = (const Expr<A>& a_) { const A& a(a_); int i; #ifdef unroll_loops for (i = 0; i<n; i += unroll) { // rozbalení smyčky na "unroll" výrazů za sebou loop_unroll<unroll, A>::do_loops(data, a, i); } // prochazíme zbytek výrazu for (;i<n; i++) { data[i] = a[i]; } #else for (i=0;i<n; i++) { data[i] = a[i]; } #endif }
Rozbalování smyček v gcc
Rozbalení smyček lze dosáhnout i pomocí přepínače gcc -funroll-loops. Což samozřejmě vede ke zvětšení spustitelného souboru a tím pádem větší spotřebě paměti, ale umožní zredukovat vyhodnocení podmínky smyčky, a tak lépe využít pipeline.