2

I have a template class, and would like to write a member method that's able to recognize what kind of type the template has been instantiated to.

I need to create a string identifier containing the following information on the type:

  • bit depth
  • signed or unsigned
  • floating point or int or char

The method should return a string composed in the following way:

string: (BIT_DEPTH)-(U|S)-(C|I|F)

BIT_DEPTH -> is the number of bits used to represent type

U | S -> describes if type is signed or unsigned

C | I | F -> describes if type is char int or floating point

I thought of a way to find to bit depth:

int bitDepth = sizeof(TemplateType) * 8;

is it ok?

But have no idea on how to find the other information I need, unless a switch-case statement like the following is ok (but don't think so):

THE FOLLOWING IS PSEUDO CODE THAT YOU SHOULD HELP ME EXPRESS IN A CORRECT SYNTAX

switch(TemplateType){

    case signed: ...;
    case unsigned: ...;

    default: ...;

}

My questions are two:

  • is bit depth calculation correct?
  • is the switch-case statement a good idea? (if yes can you please correct the syntax)
Community
  • 1
  • 1
Matteo
  • 7,924
  • 24
  • 84
  • 129
  • Have you considered run time type identification? (RTTI?) and/or dynamic_cast or reinterpret_cast and testing the result somehow? – therobyouknow Mar 01 '12 at 15:05
  • @therobyouknow actually no, I'm quite new to this stuff. Can you point me out some directions? – Matteo Mar 01 '12 at 15:07
  • The only solution is as stated above RTTI, but personally I would recommend redesigning and taking advantage of polymorphism – Chris Condy Mar 01 '12 at 15:09

2 Answers2

7

The bit calculation is OK, but can be improved by using CHAR_BIT instead of 8, see this question.

To get the other information, you can use <type_traits>, specifically:

  • std::is_signed / std::is_unsigned
  • std::is_integral / std::is_floating_point

Note that floating point types are always signed, but std::is_signed will return false, because it tests if the type is a signed integer.

Also note that char is just another integral type, so there's no standard type trait to specifically test that, but you can use a simple std::is_same<T, char>.

In code, this might look like the following:

#include <iostream>
#include <type_traits>
#include <climits> // CHAR_BIT

template<class T>
void f(){
  std::cout << sizeof(T) * CHAR_BIT << "-";
  if(std::is_integral<T>::value){
     if(std::is_signed<T>::value)
       std::cout << "S";
     else
       std::cout << "U";
     std::cout << "-";
     if(std::is_same<T, char>::value)
       std::cout << "C";
     else
       std::cout << "I";
  }else if(std::is_floating_point<T>::value){
    std::cout << "S-F";
  }
  std::cout << "\n";
}

Live example on Ideone.

Note that bool counts as unsigned integer, but that is easily fixed. Also note that the compiler will spew a bunch of warnings regarding "conditional expression is constant", so that can be improved, but this should suffice as a demonstration.

Community
  • 1
  • 1
Xeo
  • 129,499
  • 52
  • 291
  • 397
2

To add to Xeo's answer, you can remove those warnings by doing this all at compile time with std::enable_if. For instance:

template<typename T>
inline
typename std::enable_if<std::is_signed<T>::value, char>::type
sign() { return 'S'; }

template<typename T>
inline
typename std::enable_if<std::is_unsigned<T>::value, char>::type
sign() { return 'U'; }

One thing to look out for, though, is that is_signed for float is false!

Cory Nelson
  • 29,236
  • 5
  • 72
  • 110
  • Or you could make a `char sign[2] = { 'U', 'S' };` and index with `sign[std::is_signed::value]`. – Xeo Mar 01 '12 at 15:33
  • I just noticed that you'd rather use `std::is_unsigned` and flip the array elements. That way, the result will be correct even for floating point types. – Xeo Mar 03 '12 at 10:07