2011-12-02 20 views
7

निम्नलिखित कोड में, initialize() संकलन-समय बहुरूपता के आधार पर एक विधि को दिखाता है। संकलित initialize() का संस्करण int2type<true> और int2type<false> पर निर्भर करता है, जिनमें से केवल एक दिए गए टेम्पलेट पैरामीटर T के लिए सत्य होगा।डेटा सदस्यों के लिए संकलन-समय पॉलीमोर्फिज्म

यह सिर्फ इतना है कि डेटा सदस्य T* m_datum;int2type<true> और int2type<false> दोनों के लिए काम करेंगे।

अब, मैं std::vector<T> m_datum; को int2type<false> संस्करण को बदलना चाहते हैं, तो मेरे सवाल है, मैं अपने कोड कैसे संपादित कर सकता है ताकि डाटा सदस्य m_datumint2type<> पर बहुरूपी है?

नोट: कृपया नीचे दिए गए कोड के पीछे तर्क पर ध्यान न दें - इसके बजाय, मैं डेटा सदस्यों के लिए संकलन समय बहुरूपता को प्राप्त करने के यांत्रिकी पर ध्यान केंद्रित करना चाहते हैं।

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

सी ++ 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

सी ++ 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! 
} 

सी ++ 03 समाधान

आप एक metafunction लिख सकते हैं और आंशिक रूप से इस विशेषज्ञ इस प्रकार है:

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

तो जब whattrue, data_type बाहर बारी T* होगा, वरना यह है वांछित के रूप में std::vector<T> होगा।

किसी भी मामले में, आपको int2type क्लास टेम्पलेट की आवश्यकता नहीं है। बस इसे अपने कोड से हटा दें। आप इसके बिना क्लीनर कोड लिख सकते हैं।

+1

यह 'type' बजाय' data_type' – Abyx

+0

@Abyx का उपयोग करने के लिए और अधिक परंपरागत है: हाँ। मैं सहमत हूं, और संपादित किया। :-) – Nawaz

+1

+1: आने वाले मानक की मानक लाइब्रेरी को जानने के लिए, साथ ही ओपी के 'int2type <> 'detour को हटाकर क्लीनर कोड को प्रोत्साहित करने के लिए। –

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; 
}; 
संबंधित मुद्दे