2012-09-11 16 views
6

Czytałem o systemie szablonów w języku D i natknąłem się na nietypową konstrukcję, static if.Dlaczego warto używać statycznego w D?

Z tego, co udało mi się uchwycić, jest oceniany podczas kompilacji, ale z tego, co przeszukałem, przykład pokazany here nie całkiem oświecił mnie.

template Factorial(ulong n) 
{ 
    static if(n < 2) 
     const Factorial = 1; 
    else 
     const Factorial = n * Factorial!(n - 1); 
} 

Co robi static if i kiedy należy go używać?

+0

nie dostać czego tak naprawdę oczekujesz, proszę rozwiąż problem. –

+3

W jaki sposób jest to równoznaczne z C++? –

+0

@R. Martinho Fernandes Z tego, co wiem, jest to zamierzone jako superseed z C++ – coredump

Odpowiedz

11

D static if jest podstawą do "kompilacji warunkowej" i odgrywa ważną rolę wszędzie tam, gdzie musi zostać podjęta decyzja dotycząca kompilacji w odniesieniu do wariantu kodu.

Od D nie posiada preprocesora, rzeczy takie jak

#ifdef xxx 
compile_this_piece_of_code 
#endif 

może stać

static if(xxx) 
{ 
    compile_this_pece_of_code 
} 

podobnie metaprogramming może zdarzyć się również poprzez statyczny, jeżeli:

template<int x> 
struct traits 
{ some definition calculated from x }; 

template<> 
struct traits<0> 
{ same definitions for the 0 particular case } 

może być

template(int x) 
{ 
    static if(x==0) 
    { some definitions } 
    else 
    { some other same definitions } 
    even more definition common in the two cases 
} 
+0

Dzięki. Myślę, że to, co zdezorientowało mnie, to taka funkcja, jak użycie. – coredump

+0

Btw. Pierwszy przykład nie będzie się kompilował. Dla tego D ma 'wersję (XXX) {} else {}' – DejanLekic

+1

To zależy od tego, czym jest xxx: jeśli jest to symbol, wersja jest instrukcją, jeśli jest wyrażeniem stałym static_if działa. Odpowiednim przykładem jest najprawdopodobniej '#ifdef ...' ale '#if ....' –

3

Przykład Wikipedia jest rzeczywiście bardzo prosty:

template Factorial(ulong n) 
{ 
    static if(n < 2) 
     const Factorial = 1; 
    else 
     const Factorial = n * Factorial!(n - 1); 
} 

Jest to tytułowa szablon (patrz komentarz Jonathana poniżej). n jest parametrem szablonu. A więc, jeśli zamiast tego napisałeś:

template Factorial(ulong n) 
{ 
    if(n < 2) // NOTE: no static here 
     const Factorial = 1; 
    else 
     const Factorial = n * Factorial!(n - 1); 
} 

? - To nie zadziała. Sprawdź http://dpaste.dzfl.pl/3fe074f2. Powodem jest fakt, że statyczne jeśli i "normalne", jeśli mają inną semantykę. static if przyjmuje wyrażenie przypisania (http://dlang.org/version.html, sekcja "Statyczne, jeśli"), które jest oceniane przy czasie kompilacji, natomiast normalne, jeśli przyjmuje wyrażenie, które jest oceniane w czasie wykonywania.

Static if to tylko jeden ze sposobów na "kompilację warunkową" wspomnianą przez Emilio. D ma również słowo kluczowe version. Więc pierwszy warunkowy przykład kompilacja Emilia (który nie działa w D) staje się coś takiego:

version (XXX) { 
    // XXX defined 
} else { 
    // XXX not defined 
} 

Jeśli chcesz użyć statycznego czy do tego, by napisać coś takiego:

enum int XXX = 10; 
static if (XXX == 10) { 
    pragma(msg, "ten"); 
} 
+3

Factorial nie jest funkcją szablonu. To tytułowy szablon. Zastosowania szablonu zostają zastąpione wynikiem szablonu, który jest symbolem wewnątrz szablonu o tej samej nazwie, co szablon - np. 'Factorial! 5' zmienia się na' 120'. Jest to całkowicie konstrukcja czasu kompilacji. Jest to całkowicie odmienne od funkcji szablonowej, która jest nazywana jak każda inna funkcja, ale jest tworzona inaczej, w zależności od typów jej argumentów. Opierając się na twojej odpowiedzi, domyślam się, że rozumiesz to i po prostu błędnie posługujesz się terminologią, ale wprowadzisz zamieszanie takim, jakie jest. –

+0

Prawidłowo. :) Zamierzam zaktualizować moją odpowiedź, aby terminologia była właściwa. – DejanLekic

0

Andrei Alexandrescu ostatnio nazywał inteligentne użycie static if "Design by Introspection", z kilkoma świetnymi przykładami (video, slides).

Bezpośrednim przykładem z jego wykładu byłby implementacja ogólnego kontenera, takiego jak tablica haszująca za pomocą funkcji Robin Hood hashing, gdzie dodatkowe dane (liczba sond) są przechowywane przy każdym wpisie w tabeli. Z static if możemy zoptymalizować pamięć automatycznie poprzez umieszczenie licznika sondy obok klucza opartego na jego umiejscowienie, optymalizować szerokość całkowitą dla indeksu itd

Parafraza z Dyskusja:

struct RobinHashTable(K, V, size_t maxLength) { 
    static if (maxLength < ushort.max-1) { 
    alias CellIdx = ushort; 
    } else { 
    alias CellIdx = uint; 
    } 

    static if (K.sizeof % 8 < 7) { 
    align(8) struct KV { 
     align(1): 
     K k; 
     ubyte cellData; 
     align(8): 
     V v; 
    } 
    } else { 
    align(8) struct KV { 
     align(8): 
     K k; 
     V v; 
     align(1): 
     ubyte cellData; 
    } 
    } 
} 
Powiązane problemy