2009-02-24 13 views
19

Sto cercando un modo per identificare i tipi di primitivi in ​​una definizione di classe modello.Identificazione dei tipi primitivi nei modelli

Voglio dire, avendo questa classe:

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

è che non c'è alcun modo per "attuare" isPrimitiveType().

risposta

22

UPDATE: Dal momento che C++ 11, utilizzare il modello is_fundamental dalla libreria standard:

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

Al fine di salvare l'overhead funzione di chiamata, utilizzare le strutture:

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 { 
     // ... 
    } 
} 

Come altri hanno sottolineato, puoi risparmiare tempo implementandolo da solo e usa is_fundamental dalla libreria Boost Type Traits, che sembra fare esattamente la stessa cosa.

+0

Si noti inoltre che l'inverso esiste: 'std :: is_class', ad es.https://stackoverflow.com/questions/11287043/is-there-a-way-to-specialize-a-template-to-target-primitives –

1

Supponendo che per "Tipo primitivo" si intenda i tipi predefiniti, è possibile eseguire una serie di specializzazioni di modelli. Il tuo codice sarebbe diventato:

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

Il seguente esempio (. Prima ha postato in comp.lang.C++ moderato) illustra con specializzazione parziale di stampare cose in modo diverso a seconda del tipo o meno sono built-in.

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

questo ha aiutato, grazie! – Ben

2

Non può essere fatto esattamente come richiesto. Ecco come si può fare:

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

si può ottenere un avvertimento se si mette il valore di isPrimitive direttamente all'interno dell'istruzione se. Questo è il motivo per cui ho introdotto una variabile temporanea.

2

ennesimo esempi simili:

#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

La tua versione è un po 'più efficiente della mia, ma ho considerato che non ha compensato il costo di leggibilità. –

+0

Probabilmente ci sono ancora più modi per farlo. Quanto sopra è stato rapidamente hackerato per testare l'idea ... – Anonymous

5

Credo che questo può fare il lavoro abbastanza bene, senza più specializzazioni:

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

} 

e l'uscita è:

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

Ci è un modo migliore - usando SFINAE. Con SFINAE non devi elencare tutti i tipi primitivi. SFINAE è una tecnica che dipende dall'idea che quando la specializzazione del modello fallisce ricade su un modello più generale. (sta per "Errore di specializzazione non è un errore").

Inoltre, non si definisce realmente se si considera un puntatore un tipo primitivo, quindi creerò modelli per tutte le combinazioni.

// 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 > { }; 
Problemi correlati