Friday, March 23, 2012

Type Traits

Hello everybody,
Lately I have been snowed under work, in fact, I still. But I'm posting anyway ^ ^

Well, here's an introduction to some features of templates type traits.

Notice that this post is just an introduction and if you don't see the utility now you will see in further posts. Just say that generic programming can sometimes be not generic enough.

Starting to take a look to the standard way to check types of variables.

The standard provide some ways to do it. Although has his limitations and even isn't much effective but
allows to compare or even read the type of variables.

Doing this task I'm using typeid that return a std::type_info where is implemented some
methods like name in order to return a human-readable.

I don't know why my compiles expres int as i, I think that is not much normal because I have seen
many examples where typeid().name return the word int, not i, but in fact don't care.


// type_info example
#include <iostream>
#include <typeinfo>
using namespace std;

struct Base {};
struct Derived : Base {};

//using virtual; being polymorphic
struct Poly_Base {virtual void Member(){}};
struct Poly_Derived: Poly_Base {};

int main() {
     int i;
     int *p_int = 0;
     double array_d[10];

     cout << "    int is: " << typeid(int).name() << endl;
     cout << "      i is: " << typeid(i).name() << endl;
     cout << "  int==i? : " << boolalpha << 
           (typeid(i) == typeid(int)) << endl;
            //with boolapha we'll print true/false inside of 1/0
     cout << "  p_int is: " << typeid(p_int).name() << endl;
     cout << " *p_int is: " << typeid(*p_int).name() << endl;
     cout << "array_d is: " << typeid(array_d).name() << endl << endl;
   
     // non-polymorphic types:
     Derived derived;
     Base* pbase = &derived;
     cout << "derived is: " << typeid(derived).name() << endl;
     cout << "  pBase is: " << typeid(pbase).name() << endl;
     cout << " *pbase is: " << typeid(*pbase).name() << endl;
     cout << " same type? "; 
     cout << boolalpha <<( typeid(derived)==typeid(*pbase) ) 
          << endl << endl;

     // polymorphic types:
     Poly_Derived polyderived;
     Poly_Base* ppolybase = &polyderived;
     cout << "polyderived is: " << typeid(polyderived).name() << endl;
     cout << "  ppolybase is: " << typeid(ppolybase).name() << endl;
     cout << " *ppolybase is: " << typeid(*ppolybase).name() << endl;
     cout << boolalpha << "same type? " << 
           ( typeid(polyderived)==typeid(*ppolybase) ) << endl << endl;
}

Output:


    int==i? : true
    p_int is : Pi
  *p_int is : i
array_d is : A10_d

derived is : 7Derived
  pBase is : P4Base
 *pbase is : 4Base
 same type? false

polyderived is : 12Poly_Derived
   ppolybase is : P9Poly_Base
 *ppolybase is : 12Poly_Derived
        same type? true

Useful? Could be.
Although, as I said, it has some limitations, for example, what happens if I want to compare an
usigned int and an int, is it equal? The answer is no; false.

So, now, I want to show how we could do this task using temples. The behind idea is argument deduction and specialization.



#include <iostream>

template<class T>
struct is_int{
     static const bool value = false;
};
template<>
struct is_int<int>{
     static const bool value = true;
};
template<>
struct is_int<unsigned int>{
     static const bool value = true;
};
template<>
struct is_int<char>{
     static const bool value = true;
};

class A{};

using namespace std;

int main() {
     cout << "is int?: " << boolalpha << is_int<int>::value << endl;
     cout << "is unsigned int?: " << boolalpha 
          << is_int<unsigned int>::value << endl;
     cout << "is string?: " << boolalpha << is_int<string>::value << endl;
     cout << "is A?: " << boolalpha << is_int<A>::value << endl;
}

Output:


is int?: true
is unsigned int?: true
is string?: false
is A?: false

Finally, just say that boost library provide many of this template functions.


#include <boost/type_traits>


And even functions like:

is_pointer<T>
is_arithmetic<T>
is_function<T>
is_class<T>
is_polymorphic<T>
has_trivial_constructor<T>

Awesome, I know.


Also, I wanted to mention to the new decltype that is introduced in the new version of C++,
this one will be a tricky form to declare variables that you don't know how, because his complexity
can be complex like templates. It's not exactly related with what I explained but I think that
may be interesting to someone.

No comments:

Post a Comment