Reputation: 4487
I'm using Visual Studio 2005 and I've got such a method/function:
template<typename I>
void MyFunction(I &value)
{
//some operations
UI unsigned_type = static_cast<UI>(value);
}
Where the "I" is an integer type, and the "UI" should be an adequate usigned type. For example for 64bit integer type as the "I", the "UI" should be a 64bit unsigned integer type.
How can I do that?
Secondly, can I assure, that "I" will be always an integer type?
Thirdly I cannot use Boost ;).
Upvotes: 0
Views: 1976
Reputation: 55395
If you can't use boost, you've got no choice but to implement some type-traits machinery yourself. It might be a bit tedious, but here's how you might go about it:
// convinience base classes
template<typename T, T Value>
struct constant { static const T value = Value; };
typedef constant<bool, true> true_type;
typedef constant<bool, false> false_type;
// a trait to check if two types are the same
template<typename T, typename U>
struct is_same : false_type {};
template<typename T>
struct is_same<T,T> : true_type{};
// a trait to check if type is integral, based on is_same
// it's missing wchar_t and bool
#define SAME(T,U) is_same<T,U>::value
template<typename T>
struct is_integral : constant<bool,SAME(T,char) ||
SAME(T,signed char) ||
SAME(T,unsigned char) ||
SAME(T,short) ||
SAME(T,unsigned short) ||
SAME(T,int) ||
SAME(T,unsigned int) ||
SAME(T,long) ||
SAME(T,unsigned long) ||
SAME(T,long long) ||
SAME(T,unsigned long long)> {};
// Trait class to change a type to its unsigned variant.
// The base template simply forwards the type, specializations do the work.
template<typename T>
struct identity { typedef T type; };
template<typename T>
struct make_unsigned : identity<T> {};
template<> struct make_unsigned<signed char> : identity<unsigned char>{};
template<> struct make_unsigned<short> : identity<unsigned short>{};
template<> struct make_unsigned<int> : identity<unsigned int>{};
template<> struct make_unsigned<long> : identity<unsigned long>{};
template<> struct make_unsigned<long long> : identity<unsigned long long>{};
// Utility class to enable overloads based on some compile time condition
template<bool B, typename = void>
struct enable_if { };
template<typename T>
struct enable_if<true, T> {
typedef T type;
};
// Only enable this function if I is integral
template<typename I>
typename enable_if<is_integral<I>::value>::type MyFunction(I &value)
{
typename make_unsigned<I>::type ui;
}
int main()
{
int i;
MyFunction(i); // ok
float f;
MyFunction(f); // fails
}
Upvotes: 3
Reputation: 2767
You can implement type traits for yourself. A library to use might be better but when you are not able to use on, you have to do it your own:
template<class T>
struct make_unsigned; // no implementation
template<>
struct make_unsigned<int>
{
typedef unsigned int type;
};
template<>
struct make_unsigned<unsigned int>
{
typedef unsigned int type;
};
// and all other types you need ... (possibly implemented with help of a macro)
and in your code:
template<typename I>
void MyFunction(I &value)
{
//some operations
typedef make_unsigned<I>::type UI;
UI unsigned_type = static_cast<UI>(value);
}
Of course this is not perfect, but errors are manifested at compile time in your code and you can fix it.
Edit:
If I
is not an integer type (a type for which your specialisation exists) compilation will fail.
Upvotes: 3
Reputation: 3918
I am afraid in VS2005 you cannot do that straightforward (I don't think it supports C++11 to that extent). In C++11 you can use std::is_signed< I >::value
to check if I
is signed and std::make_unsigned< I >::type
to get a corresponding unsigned type.
Upvotes: 3