2012-09-05 9 views
5

tengo el siguiente código dentro de una clase de C++:Turning # de ifdef en un metaprograma plantillas de C++

class Features 
{ 
    #define Feature_Size_A 12345 
    #define Feature_Size_B 45678 
    #define Feature_Size_C 78901 
    //#define Feature_Size_D 14725 

    const int Feature_Sum = 0 
    #ifdef Feature_Size_A 
     + Feature_Size_A 
    #endif 
    #ifdef Feature_Size_B 
     + Feature_Size_B 
    #endif 
    #ifdef Feature_Size_C 
     + Feature_Size_C 
    #endif 
    #ifdef Feature_Size_D 
     + Feature_Size_D 
    #endif 
     ; 

    #ifdef Feature_Size_A 
     static float Feature_A[Feature_Size_A]; 
    #endif 
    #ifdef Feature_Size_B 
     static float Feature_B[Feature_Size_B]; 
    #endif 
    #ifdef Feature_Size_C 
     static float Feature_C[Feature_Size_C]; 
    #endif 
    #ifdef Feature_Size_D 
     static float Feature_D[Feature_Size_D]; 
    #endif 
}; 

Solía ​​comentar características, como la línea 4, para compilar y ejecutar diferentes pruebas. Pero ahora me gustaría tener la clase como plantilla, así que puedo instanciar varias versiones con diferentes características activadas o desactivadas en el mismo programa.

Estoy pensando en algo como esto:

template <bool Feature_A, bool Feature_B, bool Feature_C, bool Feature_D> 
class Features 
{ 
    ... 
}; 

Features<true, true, true, false> f; 

he intentado con impulso :: MPL: vector de, pero estoy luchando con dureza.

BTW: Este no es el código completo. El código original tiene 25 características.

Estoy agradecido por cada idea que no impliquen macros :-)

+0

¿Cómo se usan las funciones? ¿Se accede desde el exterior de la clase 'Features'? ¿Deberían ser accesibles con un nombre específico o es aceptable un acceso indexado? ¿Son todas matrices flotantes? –

Respuesta

3

listas tipo se puede utilizar para resolver este problema.

template<unsigned num, unsigned size, typename T> 
class Feature : public T 
{ 
public: 
    static float feature[size]; 
    static const unsigned int feature_sum = size + T::feature_sum; 
}; 
template<unsigned num, unsigned size, typename T> 
float Feature<num, size, T>::feature[size]; 
class Tail { 
public: 
    static const unsigned feature_sum = 0; 
}; 

template<unsigned num, unsigned size, typename T> 
float* get_feature_arr(Feature<num, size, T>& ref) 
{ 
    return ref.feature; 
} 

int main() { 
    Feature<1, 12345, Feature<2, 45678, Feature<4, 78901, Tail>>> TripleFeatures; 
    auto first = get_feature_arr<1>(TripleFeatures); 
    auto third = get_feature_arr<4>(TripleFeatures); 
    auto size = TripleFeatures.feature_sum; 
} 

Esto también se puede utilizar para acceder a cualquier función, independientemente de qué otras características estén o no en la lista.

Editar: Descubrí algunos de los detalles, como no definir la matriz y tratando de tener "3 características" como identificador. Le arreglaron. El código compila GCC 4.7.1.

+0

En mi humilde opinión: una solución muy elegante. Esto es exactamente lo que estaba buscando inicialmente. – PanicSheep

1

Por qué no utilizar matrices estáticamente asignados?

#include <stdio.h> 

template <bool Feature_A, bool Feature_B, bool Feature_C, bool Feature_D> 
class Features 
{ 
    static const int Feature_Size_A = 12345; 
    static const int Feature_Size_B = 45678; 
    static const int Feature_Size_C = 78901; 
    static const int Feature_Size_D = 14725; 
    static const int Feature_Sum = 0 
     + Feature_A ? Feature_Size_A : 0 
     + Feature_B ? Feature_Size_B : 0 
     + Feature_C ? Feature_Size_C : 0 
     + Feature_D ? Feature_Size_D : 0 
    ; 

public: 
    static float Feature_Vector_A[Feature_A ? Feature_Size_A : 0]; 
    static float Feature_Vector_B[Feature_B ? Feature_Size_B : 0]; 
    static float Feature_Vector_C[Feature_C ? Feature_Size_C : 0]; 
    static float Feature_Vector_D[Feature_D ? Feature_Size_D : 0]; 
}; 

Features<true, true, true, true> f1; 
Features<true, true, true, false> f2; 

int main() 
{ 
    printf("%d %d\n", sizeof(f1.Feature_Vector_D), sizeof(f2.Feature_Vector_D)); 
} 

Salida:

58900 0 
+0

Porque ahora 'feature_vector_a' existe independientemente de si' feature_d' es verdadero. – Puppy

+0

@DeadMG ver mi actualización – user1202136

+0

0 array de tamaño solo significa error de compilador para conformar compiladores de C++. No ha resuelto nada, excepto que no ha podido compilarse si alguna característica no está presente. – Puppy

1

No está claro exactamente lo que las características serán exactamente, pero aquí es una solución que le permite conditionnaly incluye funciones miembro, así como datos de usuario:

namespace mpl = boost::mpl; 

// Define your features 
struct FeatureA 
{ 
    static const int size = 12345; 
    static float Feature_A[size]; 

    static void methodA() {} 
}; 
float FeatureA::Feature_A[12345]; 

struct FeatureB 
{ 
    static const int size = 45678; 
    static char Feature_B[size]; // possibly different types of data (?) 

    static void methodB() {} 
}; 
float FeatureB::Feature_B[45678]; 

struct FeatureC 
{ 
    static const int size = 78901; 
    static int Feature_C[size]; 

    static void methodC() {} 
}; 
float FeatureC::Feature_C[78901]; 


// Helper metafunction 
template <typename T> 
struct get_size 
    : mpl::int_<T::size> 
{}; 


template <typename FeaturesSeq> 
struct Features_impl 
    : mpl::inherit_linearly< 
     FeaturesSeq, 
     mpl::inherit<mpl::_, mpl::_> 
    >::type 
{ 
    static const int Feature_Sum = 
     mpl::accumulate< 
      FeaturesSeq, 
      mpl::int_<0>, 
      mpl::plus< 
       mpl::_1, 
       get_size<mpl::_2> 
      > 
     >::type::value; 
}; 

template <typename... F> 
using Features = Features_impl<mpl::vector<F...>>; 


#include <iostream> 

int main() 
{ 
    typedef Features<FeatureA, FeatureC> F; 

    std::cout << F::Feature_Sum << '\n'; 

    F::Feature_A[0] = 12.0f; 
    F::methodA(); 

    F::methodC(); 
} 

Si todas sus características son realmente sólo flotador matrices, como en el ejemplo, se puede utilizar una clase genérica Feature

template <int Size> 
struct Feature 
{ 
    static float data[Size]; 
}; 
template <int Size> 
float Feature::data[Size]; 

y almacenar especializaciones de esta clase en vectores de MPL:

typedef mpl::vector<Feature<1234>, Feature<5678>> Features; 

mpl::at_c<Features, 0>::type::data[0] = 12.0f; 
// could be encapsulated into a helper function 

Sin más información sobre el propósito de estas características, es difícil proporcionar una respuesta más completa.