2009-02-24 4 views
19

Tôi đang tìm cách xác định các kiểu nguyên thủy trong định nghĩa lớp mẫu.Xác định các kiểu nguyên thủy trong các mẫu

Ý tôi là, có lớp này:

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

Có cách nào để "thực hiện" isPrimitiveType().

Trả lời

22

CẬP NHẬT: Kể từ C++ 11, sử dụng is_fundamental mẫu từ thư viện chuẩn:

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

Để tiết kiệm các chi phí chức năng cuộc gọi, sử dụng cấu trúc:

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

Như những người khác đã chỉ ra, bạn có thể tiết kiệm thời gian của mình tự thực hiện điều đó một mình và sử dụng is_fundamental từ Thư viện kiểu Boost Traits, có vẻ giống hệt như vậy.

+0

Cũng lưu ý rằng cuộc trò chuyện tồn tại: 'std :: is_class', ví dụ:https://stackoverflow.com/questions/11287043/is-there-a-way-to-specialize-a-template-to-target-primitives –

1

Giả sử theo 'Loại nguyên thủy' nghĩa là các loại được tạo sẵn, bạn có thể thực hiện một loạt chuyên môn về mẫu. Mã của bạn sẽ trở thành:

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

Ví dụ sau (. đầu tiên posted in comp.lang.C++ kiểm duyệt) minh họa sử dụng chuyên môn hóa một phần để in những thứ khác nhau tùy thuộc vào việc hay không được tích hợp sẵn trong các loại.

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

điều này đã giúp, cảm ơn! – Ben

2

Không thể thực hiện chính xác theo cách bạn đã hỏi. Sau đây là cách nó có thể được thực hiện:

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

Bạn có thể nhận được một cảnh báo nếu bạn đặt giá trị của isPrimitive trực tiếp bên trong nếu tuyên bố. Đây là lý do tại sao tôi giới thiệu một biến tạm thời.

2

Tuy nhiên, một ví dụ tương tự:

#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

Phiên bản của bạn hiệu quả hơn một chút, nhưng tôi cho rằng nó không bù đắp cho chi phí dễ đọc. –

+0

Có lẽ thậm chí còn có những cách làm đẹp hơn nữa. Ở trên đã nhanh chóng bị hack trong vim để kiểm tra ý tưởng ... – Anonymous

5

Tôi đoán đây có thể thực hiện công việc khá độc đáo, không nhiều chuyên ngành:

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

} 

Và kết quả là:

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

Có là một cách tốt hơn - sử dụng SFINAE. Với SFINAE bạn không cần phải liệt kê ra mọi loại nguyên thủy. SFINAE là một kỹ thuật phụ thuộc vào ý tưởng rằng khi chuyên môn hóa mẫu không thành công, nó sẽ trở lại một khuôn mẫu chung chung hơn. (viết tắt của "Thất bại chuyên môn không phải là lỗi").

Ngoài ra, bạn không thực sự xác định xem bạn có coi con trỏ là kiểu nguyên thủy hay không, vì vậy, tôi sẽ làm cho bạn mẫu cho tất cả các kết hợp.

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