Adrian
Adrian

Reputation: 10911

How do I detect if a template parameter is a builtin or not?

I want to use SFINAE to stop from explicitly calling the destructor because MSVS 2010 considers it an error when done on a builtin type pointer.

How would I do this?

Upvotes: 0

Views: 245

Answers (3)

Rajeev
Rajeev

Reputation: 203

With the following type function we can determine whether a type is a class type:

// traits/isclasst.hpp 

template<typename T> 
class IsClassT { 
  private: 
    typedef char One; 
    typedef struct { char a[2]; } Two; 
    template<typename C> static One test(int C::*); 
    template<typename C> static Two test(…); 
  public: 
    enum { Yes = sizeof(IsClassT<T>::test<T>(0)) == 1 }; 
    enum { No = !Yes }; 
}; 

This template uses SFINAME principle.
The following program uses this type function to test whether certain types and objects are class types:

// traits/isclasst.cpp 

#include <iostream> 
#include "isclasst.hpp" 

class MyClass { 
}; 

struct MyStruct { 
}; 

union MyUnion { 
}; 

void myfunc() 
{ 
} 

enumE{e1}e; 

// check by passing type as template argument 
template <typename T> 
void check() 
{ 
    if (IsClassT<T>::Yes) { 
        std::cout << " IsClassT " << std::endl; 
    } 
    else { 
        std::cout << " !IsClassT " << std::endl; 
    } 
} 

// check by passing type as function call argument 
template <typename T> 
void checkT (T) 
{ 
    check<T>(); 
} 

int main() 
{ 
    std::cout << "int: "; 
    check<int>(); 

    std::cout << "MyClass: "; 
    check<MyClass>(); 

    std::cout << "MyStruct:"; 
    MyStruct s; 
    checkT(s); 

    std::cout << "MyUnion: "; 
    check<MyUnion>(); 

    std::cout << "enum:    "; 
    checkT(e); 

    std::cout << "myfunc():"; 
    checkT(myfunc); 
} 
The program has the following output:

int:      !IsClassT 
MyClass:  IsClassT 
MyStruct: IsClassT 
MyUnion:  IsClassT 
enum:     !IsClassT 
myfunc(): !IsClassT 

Upvotes: 0

Daniel Frey
Daniel Frey

Reputation: 56863

You might look at it from the wrong angle: You shouldn't exclude what does not work, you should detect what does work. In your case, you are trying to check if a given type T is a class and hence you could call the destructor.

That said, you want std::is_class. If it is not available for your compiler, there is Boost.TypeTraits' boost::is_class available which works with VC++ 8 and newer.

Upvotes: 2

Strings
Strings

Reputation: 1683

This shows how to specialize a function so it is called for fundamental data types in C++.

template < class T>
void delete_object(T, typename std::enable_if<std::is_arithmetic<T>::value>::type* = 0) {
    // Do nothing because this is not an object
}

template<class T>
void delete_object(T* object) {
    delete object;
}

int main()
{
    int arithmetic1 = 1;
    delete_object(arithmetic1);
    float arithmetic2 = 1;
    delete_object(arithmetic2);
    Object* object1 = new Object();
    delete_object(object1);

    return 0;
}

Here are the other fundamental tests

std::is_integral<>       - 'char' up to 'long long'
std::is_floating_point   - 'float' up to 'long double'
std::is_signed<>         - signed types
std::is_unsigned<>       - unsigned types
std::is_arithmetic       - is_integral<> OR is_floating_point<>
std::is_fundamental<>    - is_arithmetic<> OR 'void'

Upvotes: 1

Related Questions