tags:

views:

385

answers:

6

Hello

I am looking for a way to identify primitives types in a template class definition.

I mean, having this class :

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

Is there is any way to "implement" isPrimitiveType().

+6  A: 
// 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;
    }
 }

In order to save the function call overhead, use 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 {
        // ...
    }
}

As others have pointed out, you can save your time implementing that by yourself and use is_fundamental from the Boost Type Traits Library, which seems to do exactly the same.

Ferdinand Beyer
Yes, but what I want is specilize my class *for all* primitives types :/
Ben
See my edited answer.
Ferdinand Beyer
+6  A: 

Boost TypeTraits has plenty of stuff.

Anton Gogolev
+1  A: 

Assuming by 'Primitive Type' you mean the built in types you can do a series of template specializations. Your code would become:

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();
}
Andrew Khosravian
+2  A: 

The following example (first posted in comp.lang.c++.moderated) illustrates using partial specialisation to print things differently depending on whether or not they are built-in types.

// 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;
}
anon
this helped, thanks !
Ben
A: 

It cannot be done exactly the way you asked. Here is how it can be done :

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

You may get a warning if you put the value of isPrimitive directly inside the if statement. This is why i introduced a temporary variable.

Benoît
+2  A: 

Yet another similar examples:

#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();
}
Anonymous
Your version is a bit more efficient that mine, but i considered that it did not compensate for the readability cost.
Benoît
Probably there are even nicer ways of doing this. The above was quickly hacked in vim to test the idea...
Anonymous