2011-12-02 10 views
7

W poniższym kodzie initialize() ilustruje metodę opartą na polimorfizmie kompilacji. Wersja skompilowana initialize() zależy od int2type<true> i int2type<false>, z których tylko jedna będzie prawdziwa dla danego parametru szablonu T.Polimorfizm czasu kompilacji dla danych członkowskich

Tak się składa, że ​​element danych T* m_datum; będzie działać zarówno dla int2type<true> i int2type<false>.

Teraz chcę zmienić wersję int2type<false> do std::vector<T> m_datum;, więc moje pytanie brzmi, jak mogę zmodyfikować mój kod tak, że element danych m_datum jest polimorficzny na int2type<>?

Uwaga: proszę ignorować przesłanki leżące poniżej kod - zamiast, chciałbym skupić się na mechanice osiągnięcia polimorfizm czasu kompilacji dla członków danych.

#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 rozwiązanie, oparte na zaleceniach Nawaz za

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

Odpowiedz

8

C++ 11 Rozwiązanie

Zastosowanie std::conditional jak:

#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 Rozwiązanie

Można napisać metafunkcji i częściowo specjalizują się to w następujący sposób:

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

Więc kiedy what jest true, data_type okaże się być T*, albo go będzie std::vector<T>, zgodnie z życzeniem.

W obu przypadkach nie potrzebujesz szablonu klasy int2type. Po prostu usuń to ze swojego kodu. Możesz napisać czystszy kod, bez niego.

+1

to bardziej konwencjonalny użyć 'type' zamiast' data_type' – Abyx

+0

@Abyx: Tak. Zgadzam się i edytuję. :-) – Nawaz

+1

+1: Za poznanie standardowej biblioteki nadchodzącego standardu, plus za zachęcanie do czystszego kodu przez omijanie objazdu OP "int2type <>". –

5

Jak o:

// 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; 
}; 
Powiązane problemy