2012-09-11 6 views
6

Ho letto del sistema di template nel linguaggio D e ho trovato un costrutto insolito, static if.Perché usare static se in D?

Da quello che sono riuscito a capire è valutato al momento della compilazione, ma da quello che ho cercato, l'esempio mostrato here non mi ha abbastanza illuminato.

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

Cosa static if fare, e quando dovrei usarlo?

+0

non ha ottenuto che cosa ti aspetti, per favore, elabora il problema –

+3

Com'è stato codificato C++? –

+0

@R. Martinho Fernandes Da quello che so, questo è inteso come un superseed di C++ – coredump

risposta

11

il D static if è la base per "compilazione condizionale" e svolge un ruolo importante ovunque sia necessario prendere una decisione in merito alla compilazione di una variante di un codice.

Dato D non ha un preprocessore, cose come

#ifdef xxx 
compile_this_piece_of_code 
#endif 

possono diventare

static if(xxx) 
{ 
    compile_this_pece_of_code 
} 

simile, metaprogrammazione può avvenire anche tramite statico se:

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

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

può essere

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

Grazie. Penso che ciò che mi ha confuso era la funzione come l'uso. – coredump

+0

Btw. Il primo esempio non verrà compilato. Per questo D ha la 'versione (XXX) {} else {}' – DejanLekic

+1

Dipende da cosa è effettivamente xxx: se è un simbolo, la versione è l'istruzione, se è un'espressione costante static_if funziona. L'esempio giusto è molto probabilmente non '#ifdef ...' ma '#if ....' –

3

L'esempio di Wikipedia è in realtà piuttosto semplice:

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

Si tratta di un modello omonimo (Si veda il commento di Jonathan sotto). n è il parametro del modello. Quindi, cosa succede se invece hai scritto:

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

? - Non funzionerà. Controllare http://dpaste.dzfl.pl/3fe074f2. La ragione è che statico se e "normale" se ha semantica diversa. static if accetta un'espressione di assegnazione (http://dlang.org/version.html, sezione "Statico Se") valutata al tempo di compilazione, mentre normale se accetta un'espressione valutata in fase di esecuzione.

Static if è solo un modo per eseguire la "compilazione condizionale" menzionata da Emilio. D ha anche la parola chiave version. Quindi, primo esempio la compilazione condizionale di Emilio (che non funziona in D) diventa qualcosa di simile:

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

Se si desidera utilizzare statico se per questo, si potrebbe scrivere qualcosa di simile:

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

Factorial non è una funzione modello. È un modello omonimo. Gli usi del modello vengono sostituiti con il risultato del modello che è il simbolo all'interno del modello con lo stesso nome del modello, ad es. 'Factorial! 5' diventa' 120'. È interamente un costrutto di tempo di compilazione. Questo è completamente diverso da una funzione basata su un modello che è chiamata come qualsiasi altra funzione, ma è istanziata in modo diverso a seconda dei tipi dei suoi argomenti. Basandoti sulla tua risposta, suppongo che tu capisca e abbia la terminologia sbagliata, ma causerai confusione così com'è. –

+0

corretto. :) Ho intenzione di aggiornare la mia risposta in modo che la terminologia sia corretta. – DejanLekic

0

Andrei Alexandrescu ha recentemente definito l'uso intelligente di static if "Design by Introspection", con alcuni grandi esempi (video, slides).

Un esempio diretto del suo intervento consiste nell'implementare un contenitore generico come una tabella hash utilizzando l'hashing di Robin Hood, dove viene conservato un dato aggiuntivo (numero di probe) con ogni voce nella tabella. Con static if siamo in grado di ottimizzare la memoria automaticamente posizionando il conteggio della sonda accanto al tasto in base al suo allineamento, ottimizzare la larghezza intero per il tipo di indice, ecc

parafrasato dal discorso:

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; 
    } 
    } 
}