2011-12-02 20 views
7

在以下代碼中,initialize()說明了一種基於編譯時多態性的方法。 initialize()的版本編譯取決於int2type<true>int2type<false>,對於給定的模板參數T,只有其中一個將爲真。數據成員的編譯時多態性

碰巧的數據成員T* m_datum;,才能既爲int2type<true>int2type<false>工作。

現在,我想的int2type<false>版本改爲std::vector<T> m_datum;,所以我的問題是,如何我修改我的代碼,以便數據成員m_datum是多態的int2type<>

注意:請忽略下面的代碼背後的原理 - 相反,我想專注於爲數據成員實現編譯時多態性的機制。

#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的解決方案的基礎上,謝里夫的建議

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

回答

8

C++ 11解決方案

使用std::conditional爲:

#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解決方案

你可以寫一元函數和部分專門這一如下:

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

所以當whattruedata_type會變成是T*,否則根據需要將爲std::vector<T>

無論哪種情況,您都不需要int2type類模板。只需從您的代碼中刪除。沒有它,你可以編寫更乾淨的代碼。

+1

它更傳統的使用'type'代替'data_type' – Abyx

+0

@Abyx的:是的。我同意,並編輯。 :-) – Nawaz

+1

+1:爲了解即將到來的標準的標準庫,以及通過避開OP的'int2type <>'繞道來鼓勵更乾淨的代碼。 –

5

如何:

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