2012-04-13 18 views
7

Teniendo en cuenta esta plantilla:Usando enable_if Opcionalmente, para añadir un miembro de estructura

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

... Quiero usar "enable_if" para que el miembro de SpecialType existe condicionalmente; es decir, solo cuando se crea una instancia de la plantilla con los tipos A = SpecialCase1 o SpecialCase2. En todos los demás casos, deseo que el miembro SpecialType falte.

En caso de que se pregunte por qué, se trata de la optimización, es decir, no llevar una carga inútil en la estructura. Soy un novato en la metaprogramación de plantillas, pero entiendo que necesito "enable_if" y dos "is_same" de alguna manera, pero no estoy seguro exactamente cómo ...

EDIT: Haciéndolo con C++ genérico (es decir, sin Boost-specific) Sería una ventaja.

Respuesta

5

Bien: utilice una clase base.

struct Empty {}; 

struct SpecialTypeCnt { SpecialType member; }; 

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

Dónde if_ se define como:

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

(También puede especializarse en un booleano)

Ahora, por supuesto, tiene que expresar su condición correctamente.


Dicho esto, es probable que no debe usar sólo un struct. En su lugar, debe usar un class que proporciona las operaciones que se deben aplicar en member. A continuación, proporciona un class Null con un comportamiento predeterminado y un class SomeType con el comportamiento específico de member.

De lo contrario, volverás a escribir la condición donde sea que necesites para "quizás" modificar member, y se hace realmente molesto rápidamente.

+2

'if_' se suele llamar' std :: conditional'. –

+0

@KerrekSB: Ah, gracias, soy un poco viejo, me temo. En Boost MPL era 'if_' :). No he excavado mucho en las nuevas bibliotecas de C++ 11 todavía:/ –

5

No necesita habilitar_si para esto. Especialice su estructura para casos especiales y deje la implementación predeterminada para el resto:

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

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

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

Eso haría porque re petición de todos los campos comunes y funciones de miembros - Quiero evitar esto (DRY). – ttsiodras

+0

@ttsiodras - use composición o herencia y haga lo que sugerí en un miembro o una clase base – bobah

2

Con el fin de no duplicar los miembros comunes:

Definir clase BaseSomething:

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

Definir clase SpecialSomething:

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

Definir clase Algo:

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

Ese es el más cercano a lo que necesito, pero seguramente esto es mucho más detallado que una sola línea de "enable_if" ... – ttsiodras

+2

Si verbose no funciona para usted, al menos debería analizar detenidamente la opción que elija usando el lenguaje C++.Puede ser muy detallado a veces. –

Cuestiones relacionadas