2009-02-24 17 views
19

मैं टेम्पलेट श्रेणी परिभाषा में प्राइमेटिव प्रकारों की पहचान करने का एक तरीका ढूंढ रहा हूं।टेम्पलेट्स में आदिम प्रकारों की पहचान

मेरा मतलब है, इस वर्ग के होने:

template<class T> 
class A{ 
void doWork(){ 
    if(T isPrimitiveType()) 
    doSomething(); 
    else 
    doSomethingElse(); 
} 
private: 
T *t; 
}; 

वहाँ किसी भी तरह से करने के लिए isPrimitiveType "लागू"() है।

उत्तर

22

अद्यतन: सी ++ 11 के बाद से, मानक पुस्तकालय से is_fundamental टेम्पलेट का उपयोग करें:

#include <type_traits> 

template<class T> 
void test() { 
    if (std::is_fundamental<T>::value) { 
     // ... 
    } else { 
     // ... 
    } 
} 

// Generic: Not primitive 
template<class T> 
bool isPrimitiveType() { 
    return false; 
} 

// Now, you have to create specializations for **all** primitive types 

template<> 
bool isPrimitiveType<int>() { 
    return true; 
} 

// TODO: bool, double, char, .... 

// Usage: 
template<class T> 
void test() { 
    if (isPrimitiveType<T>()) { 
     std::cout << "Primitive" << std::endl; 
    } else { 
     std::cout << "Not primitive" << std::endl; 
    } 
} 

क्रम समारोह कॉल उपरि, उपयोग structs बचाने के लिए:

template<class T> 
struct IsPrimitiveType { 
    enum { VALUE = 0 }; 
}; 

template<> 
struct IsPrimitiveType<int> { 
    enum { VALUE = 1 }; 
}; 

// ... 

template<class T> 
void test() { 
    if (IsPrimitiveType<T>::VALUE) { 
     // ... 
    } else { 
     // ... 
    } 
} 

जैसा कि अन्य ने बताया है, आप अपना समय बचा सकते हैं I अपने आप को पूरक और बूस्ट टाइप ट्रेट्स लाइब्रेरी से is_fundamental का उपयोग करें, जो वास्तव में वही करता है।

+0

ध्यान दें कि बातचीत भी मौजूद है: 'std :: is_class', उदा।https://stackoverflow.com/questions/11287043/is-there-a-way-to- specialize-a-template-to-target-primitives –

1

'आदिम प्रकार' द्वारा मानते हुए आपका मतलब है कि निर्मित प्रकार आप टेम्पलेट विशेषज्ञता का एक श्रृंखला कर सकते हैं। आपका कोड बन जाएगा:

template<class T> 
struct A{ 
    void doWork(); 
private: 
    T *t; 
}; 

template<> void A<float>::doWork() 
{ 
    doSomething(); 
} 

template<> void A<int>::doWork() 
{ 
    doSomething(); 
} 

// etc. for whatever types you like 

template<class T> void A<T>::doWork() 
{ 
    doSomethingElse(); 
} 
4

निम्न उदाहरण (। पहले comp.lang.c में ++ तैनात संचालित) आंशिक विशेषज्ञता का उपयोग कर कुछ अलग पर किया जाए या नहीं वे कर रहे हैं प्रकार में निर्मित आधार पर मुद्रित करने के लिए दिखाता है।

// some template stuff 
//-------------------- 
#include <iostream> 
#include <vector> 
#include <list> 

using namespace std; 

// test for numeric types 
//------------------------- 
template <typename T> struct IsNum { 
    enum { Yes = 0, No = 1 }; 
}; 


template <> struct IsNum <int> { 
    enum { Yes = 1, No = 0 }; 
}; 


template <> struct IsNum <double> { 
    enum { Yes = 1, No = 0 }; 
}; 

// add more IsNum types as required 

// template with specialisation for collections and numeric types 
//--------------------------------------------------------------- 
template <typename T, bool num = false> struct Printer { 
    void Print(const T & t) { 
     typename T::const_iterator it = t.begin(); 
     while(it != t.end()) { 
      cout << *it << " "; 
      ++it; 
     } 
     cout << endl; 
    } 
}; 

template <typename T> struct Printer <T, true> { 
    void Print(const T & t) { 
     cout << t << endl; 
    } 
}; 

// print function instantiates printer depoending on whether or 
// not we are trying to print numeric type 
//------------------------------------------------------------- 
template <class T> void MyPrint(const T & t) { 
    Printer <T, IsNum<T>::Yes> p; 
    p.Print(t); 
} 

// some test types 
//---------------- 
typedef std::vector <int> Vec; 
typedef std::list <int> List; 

// test it all 
//------------ 
int main() { 

    Vec x; 
    x.push_back(1); 
    x.push_back(2); 
    MyPrint(x);  // prints 1 2 

    List y; 
    y.push_back(3); 
    y.push_back(4); 
    MyPrint(y);  // prints 3 4 

    int z = 42; 
    MyPrint(z);  // prints 42 

    return 0; 
} 
+0

इससे मदद मिली, धन्यवाद! – Ben

2

यह आपके द्वारा पूछे जाने वाले तरीके से नहीं किया जा सकता है। यहाँ यह कैसे किया जा सकता है:

template<class T> 
class A{ 
void doWork(){ 
    bool isPrimitive = boost::is_fundamental<T>::value; 
    if(isPrimitive) 
    doSomething(); 
    else 
    doSomethingElse(); 
} 
private: 
T *t; 
}; 

आप एक चेतावनी मिल सकता है अगर आप अगर बयान के अंदर सीधे isPrimitive का मूल्य डाल दिया। यही कारण है कि मैंने एक अस्थायी चर प्रस्तुत किया।

2

फिर भी एक और इसी तरह के उदाहरण:

#include <boost/type_traits/is_fundamental.hpp> 
#include <iostream> 

template<typename T, bool=true> 
struct foo_impl 
{ 
    void do_work() 
    { 
     std::cout << "0" << std::endl; 
    } 
}; 
template<typename T> 
struct foo_impl<T,false> 
{ 
    void do_work() 
    { 
     std::cout << "1" << std::endl; 
    } 
}; 

template<class T> 
struct foo 
{ 
    void do_work() 
    { 
     foo_impl<T, boost::is_fundamental<T>::value>().do_work(); 
    } 
}; 


int main() 
{ 
    foo<int> a; a.do_work(); 
    foo<std::string> b; b.do_work(); 
} 
+0

आपका संस्करण थोड़ा अधिक कुशल है जो मेरा है, लेकिन मैंने माना कि यह पठनीयता लागत के लिए क्षतिपूर्ति नहीं करता है। –

+0

शायद ऐसा करने के अच्छे तरीके भी हैं। उपरोक्त विचार को परीक्षण करने के लिए उपरोक्त में तेजी से हैक किया गया था ... – Anonymous

5

मुझे लगता है कि यह काफी अच्छी तरह से काम कर सकते हैं, एकाधिक विशेषज्ञता के बिना:

# include <iostream> 
# include <type_traits> 

template <class T> 
inline bool isPrimitiveType(const T& data) { 
    return std::is_fundamental<T>::value; 
} 

struct Foo { 
    int x; 
    char y; 
    unsigned long long z; 
}; 


int main() { 

    Foo data; 

    std::cout << "isPrimitiveType(Foo): " << std::boolalpha 
     << isPrimitiveType(data) << std::endl; 
    std::cout << "isPrimitiveType(int): " << std::boolalpha 
     << isPrimitiveType(data.x) << std::endl; 
    std::cout << "isPrimitiveType(char): " << std::boolalpha 
     << isPrimitiveType(data.y) << std::endl; 
    std::cout << "isPrimitiveType(unsigned long long): " << std::boolalpha 
     << isPrimitiveType(data.z) << std::endl; 

} 

और उत्पादन होता है:

isPrimitiveType(Foo): false 
isPrimitiveType(int): true 
isPrimitiveType(char): true 
isPrimitiveType(unsigned long long): true 
3

वहाँ एक बेहतर तरीका है - SFINAE का उपयोग करना। SFINAE के साथ आपको हर आदिम प्रकार को सूचीबद्ध करने की आवश्यकता नहीं है। SFINAE एक ऐसी तकनीक है जो इस विचार पर निर्भर करती है कि जब टेम्पलेट विशेषज्ञता विफल हो जाती है तो यह एक और सामान्य टेम्पलेट पर वापस आती है। (यह "विशेषज्ञता विफलता एक त्रुटि नहीं है" के लिए खड़ा है)।

यदि आप पॉइंटर को आदिम प्रकार मानते हैं तो भी आप वास्तव में परिभाषित नहीं करते हैं, इसलिए मैं आपको सभी संयोजनों के लिए टेम्पलेट्स बनाउंगा।

// takes a pointer type and returns the base type for the pointer. 
// Non-pointer types evaluate to void. 
template < typename T > struct DePtr      { typedef void R; }; 
template < typename T > struct DePtr< T * >    { typedef T R; }; 
template < typename T > struct DePtr< T * const >   { typedef T R; }; 
template < typename T > struct DePtr< T * volatile >  { typedef T R; }; 
template < typename T > struct DePtr< T * const volatile > { typedef T R; }; 

// ::value == true if T is a pointer type 
template < class T > struct IsPointer      { enum { value = false }; }; 
template < class T > struct IsPointer < T *    > { enum { value = true }; }; 
template < class T > struct IsPointer < T * const   > { enum { value = true }; }; 
template < class T > struct IsPointer < T * volatile  > { enum { value = true }; }; 
template < class T > struct IsPointer < T * const volatile > { enum { value = true }; }; 

// ::value == true if T is a class type. (class pointer == false) 
template < class T > struct IsClass 
{ 
    typedef u8 yes; typedef u16 no; 
    template < class C > static yes isClass(int C::*); 
    template < typename C > static no isClass(...); 
    enum { value = sizeof(isClass<T>(0)) == sizeof(yes) }; 
}; 

// ::value == true if T* is a class type. (class == false) 
template < class T > struct IsClassPtr 
{ 
    typedef u8 yes; typedef u16 no; 
    template < class C > static yes isClass(int C::*); 
    template < typename C > static no isClass(...); 
    enum { value = sizeof(isClass< typename DePtr<T>::R >(0)) == sizeof(yes) }; 
}; 

// ::value == true if T is a class or any pointer type - including class and non-class pointers. 
template < class T > struct IsClassOrPtr : public IsClass<T> { }; 
template < class T > struct IsClassOrPtr < T *    > { enum { value = true }; }; 
template < class T > struct IsClassOrPtr < T * const   > { enum { value = true }; }; 
template < class T > struct IsClassOrPtr < T * volatile  > { enum { value = true }; }; 
template < class T > struct IsClassOrPtr < T * const volatile > { enum { value = true }; }; 


template < class T > struct IsClassOrClassPtr : public IsClass<T> { }; 
template < class T > struct IsClassOrClassPtr < T *    > : public IsClassPtr< T*    > { }; 
template < class T > struct IsClassOrClassPtr < T * const   > : public IsClassPtr< T* const   > { }; 
template < class T > struct IsClassOrClassPtr < T * volatile  > : public IsClassPtr< T* volatile  > { }; 
template < class T > struct IsClassOrClassPtr < T * const volatile > : public IsClassPtr< T* const volatile > { }; 
संबंधित मुद्दे