2009-02-24 14 views
19

テンプレートクラス定義でプリミティブ型を識別する方法を探しています。テンプレート内のプリミティブ型の識別

私はこのクラスを持つ、意味:

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

)がisPrimitiveTypeを( "実施" するためにどのような方法がありますです。

答えて

22

UPDATE:関数呼び出しのオーバーヘッド、使用の構造体を節約するために

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

:C++ 11ので、標準ライブラリからis_fundamentalテンプレートを使用

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

頼んだやり方では正確に行うことはできません。ここ はそれを行うことができる方法です。

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

あなたは if文の内側に直接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

これを行うにはさらに良い方法があります。上記はアイデアをテストするために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 > { }; 
関連する問題