2009-02-24 9 views
19

템플릿 클래스 정의에서 기본 유형을 식별 할 수있는 방법을 찾고 있습니다.템플릿의 기본 유형 식별

나는이 클래스를 가지고, 의미 :

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

는() isPrimitiveType를 "구현"할 수있는 방법이입니다.

답변

22

UPDATE는 : C++ 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; 
    } 
} 

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

다른 사람들이 지적했듯이 시간을 절약 할 수 있습니다. 너 자신에 의해 그것을 보완하고 똑같이하는 것처럼 보이는 Boost Type Traits Library에서 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

정확히 묻는대로 수행 할 수 없습니다. 여기 는 그것을 할 수있는 방법이다 : 당신이 if 문 내부에 직접 isPrimitive의 값을 넣으면

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

당신은 경고를받을 수 있습니다. 이것이 내가 임시 변수를 도입 한 이유입니다.

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

아마도이 작업을 수행하는 데 더 좋은 방법이있을 것입니다. 위의 내용은 아이디어를 테스트하기 위해 vim에서 빠르게 해킹되었습니다 ... – 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 > { };