2012-04-13 8 views
7

Dato questo modello:Utilizzando enable_if facoltativamente aggiungere un membro struct

template <class A> 
struct Something { 
    ... // members common to all template instantiations for all A types 
    SpecialType member; // but not this - I want this to be conditional... 
} 

... voglio usare "enable_if" per avere il membro SpecialType esiste condizionatamente; cioè, solo quando il modello viene istanziato con i tipi A = SpecialCase1 o SpecialCase2. In tutti gli altri casi, voglio che manchi il membro SpecialType.

Nel caso vi stiate chiedendo perché, questo riguarda l'ottimizzazione, ovvero non trasportare un carico utile inutile nella struttura. Sono un novizio in metaprogrammazione del modello, ma capisco che ho bisogno di "enable_if" e due "is_same" in qualche modo - non sono sicuro esattamente come, però ...

EDIT: farlo con C++ generico (cioè senza specifiche Boost) sarebbe un vantaggio.

risposta

5

Bene: utilizzare una classe base.

struct Empty {}; 

struct SpecialTypeCnt { SpecialType member; }; 

template <typename A> 
struct Something: if_< /* cond */ , SpecialTypeCnt, Empty>::type { 
}; 

Dove if_ è definito come:

template <typename, typename, typename E> struct if_ { typedef E type; }; 

template <typename T, typename E> 
struct if_<std::true_type, T, E> { typedef T type; }; 

(È anche possibile specializzarsi su un valore booleano)

Ora, naturalmente, è necessario esprimere la sua condizione in modo corretto.


Detto questo, si dovrebbe probabilmente non usare solo un struct. Invece si dovrebbe usare un class che fornisce le operazioni che devono essere applicate su member. Quindi fornisci un class Null con un comportamento predefinito e un class SomeType con il comportamento specifico per member.

Altrimenti si riscriverà la condizione ovunque sia necessario "forse" modificare member, e diventa fastidioso molto veloce.

+2

'if_' viene solitamente chiamato' std :: condizionale'. –

+0

@KerrekSB: Ah, grazie, sono un po 'un vecchio timer, temo. In Boost MPL era 'if_' :) Non ho ancora scavato molto nelle nuove librerie C++ 11:/ –

5

Non è necessario enable_if per questo. Specializza la tua struttura per casi speciali e lascia l'implementazione predefinita per il resto:

template <class A> 
struct Something 
{ 
    // your default implementation 
}; 

template <> 
struct Something<SpecialCase1> 
{ 
    // your SpecialCase1 implementation 
}; 

template <> 
struct Something<SpecialCase2> 
{ 
    // your SpecialCase2 implementation 
}; 
+0

che sarebbe causa re petizione di tutti i campi comuni e le funzioni dei membri - Voglio evitare questo (ASCIUTTO). – ttsiodras

+0

@ttsiodras - usa la composizione o l'ereditarietà e fa ciò che ho suggerito su un membro o su una classe base – bobah

2

Al fine di non duplicare i membri comuni:

Definire classe BaseSomething:

template <class A> 
     struct BaseSomething { 
      ... // members common to all template instantiations for all A types 
       }; 

Definire classe SpecialSomething:

template <class A> 
      struct SpecialSomething { 
       SpecialType member; 
       ...//SpetialType related functionality 
        }; 

Definire classe Qualcosa:

template <class A> 
      struct Something :public BaseSomething<A>{ 

        }; 



    template<> 
    struct Something<SpecialCase1>:public BaseSomething<A>{ 
        SpecialSomething<SpecialCase1> special; 
         }; 


template<> 
struct Something<SpecialCase2>:public BaseSomething<A>{ 
       SpecialSomething<SpecialCase2> special; 
        }; 
+0

Quello è il più vicino a quello di cui ho bisogno - ma sicuramente questo è molto più prolisso di una singola riga di "enable_if" ... – ttsiodras

+2

Se verbose non funziona per te allora dovresti almeno dare un'occhiata alla tua scelta di usare il linguaggio C++.A volte può essere molto prolisso. –