2013-06-10 10 views
7

Ho una funzione che analizza il file system dell'utente, riempie un vettore con i percorsi, quindi lo ordina o meno. Dato che l'utente dovrebbe essere in grado di decidere in fase di compilazione se desidera che il vettore sia ordinato o meno, io uso i modelli e le classi di helper al posto di un "statico se" molto desiderato (ma non esistente).Metaprogrammazione modello C++, soluzione "statica se" - può essere migliorata?

Considerate questo codice:

enum class Sort{Alphabetic, Unsorted}; 

template<Sort TS> struct SortHelper; 
template<> struct SortHelper<Sort::Alphabetic> 
{ 
    static void sort(vector<string>& mTarget) { sort(begin(mTarget), end(mTarget)); } 
}; 
template<> struct SortHelper<Sort::Unsorted> 
{ 
    static void sort(vector<string>&) { } 
}; 

template<Sort TS> struct DoSomethingHelper 
{ 
    static void(vector<string>& mTarget) 
    { 
     // do something with mTarget 
     SortHelper<TS>::sort(mTarget); 
    } 
}; 

Il codice che ho scritto sopra è molto semplificato dal the original, che prende più parametri di modello per consentire all'utente di personalizzare ulteriormente i risultati della funzione a tempo di compilazione .

Esiste un'alternativa all'utilizzo di tutte queste classi di supporto? Diventa davvero disordinato e difficile da leggere.

Idealmente, questo è quello che vorrei scrivere:

enum class Sort{Alphabetic, Unsorted}; 
template<Sort TS> struct DoSomethingHelper 
{ 
    static void(vector<string>& mTarget) 
    { 
     // do something with mTarget 
     static_if(TS == Sort::Unsorted) { /* do nothing */ } 
     static_if(TS == Sort::Alphabetic) { sort(begin(mTarget), end(mTarget)); } 
    } 
}; 
+1

Non esistente e [non probabile che esistano] (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3613.pdf). – Morwenn

+3

Ehm, perché ti interessa fare questo in fase di compilazione? Sembra che tu stia pensando troppo a questo. Se si esegue la scansione di un albero di directory per la prima volta, un singolo ramo di runtime sarà molto al di sotto del rumore di riferimento nell'impatto sulle prestazioni. –

+2

Se tutti i rami sono sintatticamente e semanticamente validi, è possibile utilizzare un normale 'if' e l'ottimizzatore eliminerà i rami inattivi, così come i comandi/salti non necessari. Se i rami inattivi non vengono compilati, tuttavia, gli helper sono l'unico modo. – Angew

risposta

17

Dal momento che il valore è noto al momento della compilazione (tipo non-modello di parametri) è possibile perfettamente scrivere un "normale" if:

template<Sort TS> 
void someFunction(vector<string>& mTarget) 
{ 
    if (TS == Sort::Alphabetic) { sort(begin(mTarget), end(mTarget)); } 
    // else if (TS == Sort::Unsorted) {} 
} 

il compilatore eseguirà costante piegatura e eliminazione del codice morto (se tali ottimizzazioni sono abilitati, ovviamente), e il risultato sarà e xactly lo stesso come se si usasse l'ipotetico static_if.

+1

Sembra fantastico - esiste una documentazione dettagliata su questo tipo di ottimizzazione? Mi piacerebbe sapere quando è garantito al 100%, o quando il compilatore ha problemi a farlo, ecc ... –

+0

gcc ha [questa pagina] (http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options. html) che spiega ogni singola opzione di ottimizzazione che puoi controllare, include -fdce, eliminazione del codice morto – SirGuy

+2

Non è affatto garantita dallo standard, ma è consentita (dalla clausola as-if: se non puoi raggiungere il dead code, è lo stesso di-se non è lì), ma a qualsiasi livello di ottimizzazione non banale, non ho mai visto un singolo compilatore C++ * non * farlo. Per la portabilità, rendi un semplice confronto con un valore ovvio in fase di compilazione. Si noti che il codice nel ramo deve essere legale per compilare se o se la condizione è vera. – Yakk

11

Ho paura che ci sia stato un malinteso sull'utilizzo di static_if.

Certamente è possibile utilizzare static_if (o qualsiasi altro trucco si desideri davvero) per cercare di ottenere qualche ottimizzazione, ma questo non è il suo primo obiettivo.

Il primo obiettivo di static_if è semantico. Lascia che ti dimostri con std::advance. Una tipica implementazione di std::advance utilizzerà un sensore a scegliere, in fase di compilazione, tra un O (1) implementazione (per Random Access iteratori) ed una (n) implementazione O (per gli altri):

template <typename It, typename D> 
void advance_impl(It& it, D d, random_access_iterator_tag) 
{ 
    it += d; 
} 

template <typename It, typename D> 
void advance_impl(It& it, D d, bidirectional_iterator_tag) 
{ 
    if (d > D(0)) { for (D i(0); i < d; ++i) { ++it; } } 
    else   { for (D i(0); i > d; --i) { --it; } } 
} 

template <typename It, typename D> 
void advance_impl(It& it, D d, input_iterator_tag) 
{ 
    for (D i(0); i < d; ++i) { ++it; } 
} 

e infine:

template <typename It, typename D> 
void advance(It& it, D d) 
{ 
    typename std::iterator_traits<It>::iterator_category c; 
    advance_impl(it, d, c); 
} 

Perché non utilizzare solo un if in questo caso? Perché non si compilerebbe.

  • un bidirezionale Iterator non supporta +=
  • un ingresso Iterator (o Forward Iterator) non supporta --

Pertanto, il unico modo per implementare la funzionalità è staticamente inviare a una funzione solo utilizzando le operazioni disponibili sul tipo specificato.

0

E la specializzazione dei modelli?

#include <vector> 
#include <iostream> 
#include <algorithm> 

using namespace std; 

enum class Sort { 
    Alphabetic, 
    Unsorted 
}; 

template<Sort TS> struct DoSomethingHelper { 
    static void someFunction(vector<string>& mTarget) 
    {} 
}; 

template<> struct DoSomethingHelper<Sort::Unsorted> { 
    static void someFunction(vector<string>& mTarget) { 

    } 
}; 

template<> struct DoSomethingHelper<Sort::Alphabetic> { 
    static void someFunction(vector<string>& mTarget) { 
     sort(begin(mTarget), end(mTarget)); 
    } 
}; 

int main() { 
    vector<string> v = {{"foo", "bar", "foo2", "superman", ".."}}; 

    DoSomethingHelper<Sort::Alphabetic> helper; 
    helper.someFunction(v); 

    for (string& s : v) { 
     cout << s << endl; 
    } 
    return 0; 
} 

Edit: Sono un idiota.

Problemi correlati