[v3] ext/type_traits.h

Howard Hinnant hhinnant@apple.com
Thu Sep 28 15:31:00 GMT 2006


On Sep 28, 2006, at 10:14 AM, Benjamin Kosnik wrote:

>
>> In the use cases I've personally been involved with, I had an
>> integral type T which could be either signed or unsigned, and I
>> needed to get its unsigned counterpart (or signed counterpart).
>> Actually the former (unsigned counterpart) was my more common need.
>> Having to spell that typename __add_unsigned<typename
>> __remove_signed<T>::type>::type seems cumbersome.
>
> All this seems unduly complicated to me.
>
> TR1 already has traits for is_signed or is_unsigned. Together with
> __conditional_type (hopefully spelled conditional_type in TR2 or  
> wherever) gives:
>
> // To get unsigned type.
> conditional_type(is_signed<T>::value, add_unsigned<T>::type, T)
>
> This seems reasonable to me, and quite readable.
>
> ?
>
> C++ doesn't currently have "to" traits or utils. Why add them? If you
> add this, will "to_const" be next?
>
> ;)

I just looked at the latest version of __add_unsigned in ext/ 
type_traits.h.  The above (very reasonable) recipe breaks for signed  
char.  I see no way to turn a signed char into an unsigned char.  If  
add_unsigned<signed char>::type would deliver an unsigned char  
instead of a signed char, then I think we would be set.

Similarly, both remove_unsigned<unsigned char>::type and  
remove_unsigned<char>::type should probably yield signed char instead  
of char, at least when char is unsigned.  I'd hate to say  
remove_unsigned<char>::type and get an unsigned type.

I think the basic conflict here is: Do these traits reflect syntax or  
semantics?  I'm urging the latter (and don't have strong feelings on  
what we call it).

With those changes, we don't even need your suggested recipe using  
conditional_type:

// To get unsigned type.
add_unsigned<T>::type

The condition is built into add_unsigned.

As it stands today, we would need:

// To get unsigned type.
conditional_type(is_same<T, signed char>::value, unsigned char,  
add_unsigned<T>::type)

One final nit:  add_unsigned<const short>::type yields what?  I  
recommend const unsigned short.

namespace detail
{

template <class T, bool make_const, bool make_volatile>
struct union_cv;

template <class T>
struct union_cv<T, false, false>
{
     typedef T type;
};

template <class T>
struct union_cv<T, false, true>
{
     typedef volatile T type;
};

template <class T>
struct union_cv<T, true, false>
{
     typedef const T type;
};

template <class T>
struct union_cv<T, true, true>
{
     typedef const volatile T type;
};

}

template <class T, class U>
struct union_cv
{
     typedef typename std::tr1::remove_cv<T>::type Tr;
     typedef typename std::tr1::remove_cv<U>::type Ur;
     static const bool make_const = std::tr1::is_const<T>::value ||  
std::tr1::is_const<U>::value;
     static const bool make_volatile =  
std::tr1::is_volatile<T>::value || std::tr1::is_volatile<U>::value;
     typedef typename detail::union_cv<Tr, make_const,  
make_volatile>::type type;
};

namespace detail
{
   template<typename _Value>
     struct add_unsigned
     { typedef _Value type; };

   template<>
     struct add_unsigned<char>
     { typedef unsigned char type; };

   template<>
     struct add_unsigned<signed char>
     { typedef unsigned char type; };

   template<>
     struct add_unsigned<short>
     { typedef unsigned short type; };

   template<>
     struct add_unsigned<int>
     { typedef unsigned int type; };

   template<>
     struct add_unsigned<long>
     { typedef unsigned long type; };

   template<>
     struct add_unsigned<long long>
     { typedef unsigned long long type; };
}

template <class T>
struct add_unsigned
{
     typedef typename union_cv<typename detail::add_unsigned<typename  
std::tr1::remove_cv<T>::type>::type, T>::type type;
};

union_cv probably needs a better name, but I've found it useful more  
than once.

-Howard



More information about the Libstdc++ mailing list