2011-12-02 39 views
7

En el siguiente código, initialize() ilustra un método basado en el polimorfismo en tiempo de compilación. La versión de initialize() compilada depende de int2type<true> y int2type<false>, de las cuales solo una será cierta para un parámetro de plantilla dado T.Polimorfismo en tiempo de compilación para los miembros de datos

Sucede que el miembro de datos T* m_datum; funcionará tanto para int2type<true> como para int2type<false>.

Ahora, yo quiero cambiar la versión int2type<false> a std::vector<T> m_datum;, así que mi pregunta es, ¿Cómo modificar mi código para que el miembro de datos m_datum es polimórfico en int2type<>?

Nota: ignore el razonamiento detrás del código a continuación - en su lugar, me gustaría centrarme en la mecánica de lograr el polimorfismo en tiempo de compilación para los miembros de los datos.

#include <type_traits> 
#include <stdlib.h> 

using namespace std; 

template <bool n> 
struct int2type 
{ 
    enum { value = n }; 
}; 

template< typename T > 
struct is_trivially_copyable 
{ 
    static const bool value = std::is_standard_layout<T>::value; 
}; 

template<class T> 
class Foo 
{ 
    public: 
    Foo(size_t n) : m_nr(n) 
    { 
     initialize(int2type<is_trivially_copyable<T>::value>());   
    } 
    ~Foo() { } 

    private: 
    void initialize(int2type<true>) 
    { 
     m_datum = (T*) calloc(sizeof(T), m_nr); 
    } 
    void initialize(int2type<false>) 
    { 
     m_datum = new T[m_nr]; 
    } 

    private: 
    size_t  m_nr; 
    T*   m_datum; // ok for int2type<true> 
// vector<T> m_datum; // want to change to this for int2type<false> 
}; 

class Bar 
{ 
    public: 
    Bar() { } 
    virtual ~Bar() { } 
}; 

int main(int argc, char** argv) 
{ 
    Foo<int> foo_trivial( 5); 
    Foo<Bar> foo_nontrivial(10); 

    return 0; 
} 

C++ 11 solución, basada en las recomendaciones de Nawaz

#include <type_traits> 
#include <vector> 
#include <stdlib.h> 

using namespace std; 

template< typename T > 
struct is_trivially_copyable 
{ 
    static const bool value = std::is_standard_layout<T>::value; 
}; 

template<class T> 
class Foo 
{ 
    private: 
     static const bool what = is_trivially_copyable<T>::value; 
     typedef typename std::conditional<what,T*,std::vector<T>>::type type; 

    public: 
     Foo(size_t n) : m_nr(n) 
     { 
      initialize(m_datum);  
     } 
     ~Foo() { } 

    private: 
     void initialize(T* dummy) 
     { 
      m_datum = (T*) calloc(sizeof(T), m_nr); 
     } 
     void initialize(std::vector<T>& dummy) 
     { 
      m_datum.resize(m_nr);    
     } 

    private: 
     size_t  m_nr; 
     type  m_datum; 
}; 

class Bar 
{ 
    public: 
     Bar() { } 
     virtual ~Bar() { } 
}; 

int main(int argc, char** argv) 
{ 
    Foo<int> foo_trivial( 5); 
    Foo<Bar> foo_nontrivial(10); 

    return 0; 
} 

Respuesta

8

C++ 11 Solución

Uso std::conditional como:

#include <type_traits> 

template<class T> 
class Foo 
{ 
    //some info we can use throughout the class 
    static const bool what = is_trivially_copyable<T>::value; 
    typedef typename std::conditional<what, T*, std::vector<T>>::type data_type; 

    //data members 
    data_type m_data; //this is what you need! 
} 

C++ 03 Solución

Puede escribir un metafunción y se especializan en parte este de la siguiente manera:

template<class T> 
class Foo 
{ 
    //primary template 
    template<bool b, typename T> 
    struct get { typedef T* type; }; 

    //partial specialization 
    template<typename T> 
    struct get<false, T> { typedef std::vector<T> type; }; 

    //some info we can use throughout the class 
    static const bool what = is_trivially_copyable<T>::value; 
    typedef typename get<what, T>::type data_type; 

    //data members 
    data_type m_data; //this is what you need! 
}; 

Así que cuando what es true, data_type va a llegar a ser T*, o de lo contrario será std::vector<T>, según lo desee.

En cualquier caso, no necesita la plantilla de clase int2type. Solo elimínalo de tu código. Puedes escribir código limpiador sin él.

+1

es más convencional usar 'type' en lugar de' data_type' – Abyx

+0

@Abyx: Sí. Estoy de acuerdo y editado. :-) – Nawaz

+1

+1: Ya se conoce la biblioteca estándar del próximo estándar, más para fomentar el código del limpiador al eludir el desvío 'int2type <>' del OP. –

5

¿Qué tal:

// Generic 
template <typename T, typename Arg> 
struct datum_type_dispatch {}; 

// Specialization for Arg = int2type<true> 
template <typename T> 
struct datum_type_dispatch<T, int2type<true> > 
{ 
    typedef T* type; 
}; 

// Specialization for Arg = int2type<false> 
template <typename T> 
struct datum_type_dispatch<T, int2type<false> > 
{ 
    typedef std::vector<T> type; 
}; 

template <typename T> 
class Foo 
{ 
    // ... 
private: 
    // Get the datum type based on int2type<...> 
    typedef typename datum_type_dispatch<T, int2type<is_trivially_copyable<T>::value> >::type datum_type; 

    datum_type m_datum; 
}; 
Cuestiones relacionadas