I am looking to define a template class whose template parameter will always be an integer type. The class will contain two members, one of type T
, and the other as the unsigned variant of type T
-- i.e. if T == int
, then T_Unsigned == unsigned int
. My first instinct was to do this:
template <typename T> class Range {
typedef unsigned T T_Unsigned; // does not compile
public:
Range(T min, T_Unsigned range);
private:
T m_min;
T_Unsigned m_range;
};
But it doesn't work. I then thought about using partial template specialization, like so:
template <typename T> struct UnsignedType {}; // deliberately empty
template <> struct UnsignedType<int> {
typedef unsigned int Type;
};
template <typename T> class Range {
typedef UnsignedType<T>::Type T_Unsigned;
/* ... */
};
This works, so long as you partially specialize UnsignedType
for every integer type. It's a little bit of additional copy-paste work (slash judicious use of macros), but serviceable.
However, I'm now curious - is there another way of determining the signed-ness of an integer type, and/or using the unsigned variant of a type, without having to manually define a Traits class per-type? Or is this the only way to do it?
The answer is in <type_traits>
For determining the signed-ness of a type use std::is_signed
and std::is_unsigned
.
For adding/removing signed-ness, there is std::make_signed
and std::make_unsigned
.
If you can't or don't want to depend on TR1/C++0x features, Boost.TypeTraits also offers you make_unsigned<>
et al.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With