I am using C++ (not 11) and using some libraries which have different typedefs for integer data types. Is there any way I can assert that two typedefs are the same type? I've come up with the following solution myself.. is it safe?
Thanks
template<typename T>
struct TypeTest
{
static void Compare(const TypeTest& other) {}
};
typedef unsigned long long UINT64;
typedef unsigned long long UINT_64;
typedef unsigned int UINT_32;
int main()
{
TypeTest<UINT64>::Compare(TypeTest<UINT64>()); // pass
TypeTest<UINT64>::Compare(TypeTest<UINT_64>()); // pass
TypeTest<UINT64>::Compare(TypeTest<UINT_32>()); // fail
}
In C++11, you could use std::is_same<T,U>::value.
Since you don't have C++11, you could implement this functionality yourself as:
template<typename T, typename U>
struct is_same
{
static const bool value = false;
};
template<typename T>
struct is_same<T,T> //specialization
{
static const bool value = true;
};
Done!
Likewise you can implement static_assert1 as:
template<bool> struct static_assert;
template<> struct static_assert<true> {}; //specialization
Now you can use them as:
static_assert<is_same<UINT64,UINT64>::value>(); //pass
static_assert<is_same<UINT64,UINT32>::value>(); //fail
Or you could wrap this in a macro as:
#define STATIC_ASSERT(x) { static_assert<x> static_assert_failed; (void) static_assert_failed; }
then use as:
STATIC_ASSERT(is_same<UINT64,UINT64>::value); //pass
STATIC_ASSERT(is_same<UINT64,UINT32>::value); //pass
If you use macro, then you would see the following string in the compiler generated message if the assert fails:
static_assert_failed
which is helpful. With the other information in the error message, you would be able to figure out why it failed.
Hope that helps.
1. Note that in C++11, static_assert is an operator (which operates at compile-time), not a class template. In the above code, static_assert is a class template.
Since you don't have C++11, use boost.
BOOST_STATIC_ASSERT(boost::is_same<T, U>::value);
You can write some kind of your assert function, instead of BOOST_STATIC_ASSERT.
std::type_info might help you.
Related
I have a class that looks similar to this:
class Compound
{
void* pValue0;
void* pValue1;
void* pValue2;
void* pValue3;
void* pValue4;
void* pValue5;
void* pValue6;
void* pValue7;
void* pValue8;
void* pValue9;
void* pValueA;
void* pValueB;
void* pValueC;
};
When I create a new Compound class, I allocate extra memory [sizeof(Compound) + extraSpace]. Each of the pValue's refer to an address in the extra memory.
Now, I would like to reduce the number of pValue's depending on which of them I need. Templates seem like a good fit.
So if I wanted a class Compound<0A>, I would only want pValue0 and pValueA, and then have the compiler remove all other pValues. Essentially, I would want it to then become:
template <uint Mask = 0A>
class Compound<Mask>
{
void* pValue0;
void* pValueA;
}
Is this possible? I got close with enable_if, but when I tried to limit it to a particular mask the compiler threw errors about being unable to find a type when the enable_if case was false.
Thank you all!
This might do:
template<char...>
struct flags_tag {constexpr flags_tag(){}; };
template<char...Cs>
struct make_flags{ using type=flags_tag<Cs...>; };
template<char...Cs>
struct make_flags<'0','x',Cs...>:make_flags<Cs...>{};
template<char...Cs>
struct make_flags<'0','X',Cs...>:make_flags<Cs...>{};
template<char...Cs>
using make_flags_t = typename make_flags<Cs...>::type;
template<char...Cs>
constexpr make_flags_t<Cs...> operator""_flag(){ return {}; }
template<char> struct pValue_t;
template<> struct pValue_t<'0'>{ void* pValue0 = 0; };
template<> struct pValue_t<'1'>{ void* pValue1 = 0; };
// ...
template<> struct pValue_t<'A'>{ void* pValueA = 0; };
template<> struct pValue_t<'B'>{ void* pValueB = 0; };
template<> struct pValue_t<'C'>{ void* pValueC = 0; };
template<class flags>
struct Compound;
template<char...Cs>
struct Compound< flags_tag<Cs...> >:
pValue_t<Cs>...
{};
Then you use it like:
using my_type = Compound< decltype( 0x0A_flag ) >;
int main() {
my_type test;
std::cout << test.pValue0 << test.pValueA << '\n';
}
which seems to do what you want.
I'd also disable the copy/move ctor of your Compound type, and make its other constructors private with a friend factory function.
Note that this code can generate an exponential number of classes (2^12, or 4k), and that can cause binary bloat (if any per-class code isn't inlined out of existence).
[live example]
std::conditional is similar to std::enable_if, except conditional always returns a type.
std::conditional<satisfies(Mask), void*, EmptyClass> would be the way to swap the member's types out conditionally and have it compile.
The problem is, C++ does not allow empty members. The size will be 1. To solve this problem, you'd need the empty member optimization. This will achieve the memory layout that you're asking for, but unfortunately, this will make the class members difficult to read. You can add accessor functions to mitigate this, if you think it's worth pursuing.
I am assuming that the Compound class shall contain pointers to objects of different classes and not void pointers, as you said in your comment.
I don't know if that is a good idea because I think there is something wrong in the design, but you could use tuples and template specializations on ints to select the type you want:
class Class0;
class ClassA;
template<int> struct Compound {};
template<> struct Compound<0A>
{
typedef std::tuple<Class0*, ClassA*> type;
}
// other mapping from mask to type
typename Compound<0A>::type aCompund(ptr0, ptrA);
I'm experimenting a little with type traits and template specialization. For example:
enum TestEnum
{
VALUE0 = 0,
VALUE1 = 1,
VALUE2 = 2
//... And so on...
};
template<int Value>
class cTestClass;
//specializations
template<>
class cTestClass<VALUE0>
{
static int GetVal() { return VALUE0; }
};
template<>
class cTestClass<VALUE1>
{
static int GetVal() { return VALUE1; }
};
template<>
class cTestClass<VALUE2>
{
static int GetVal() { return VALUE2; }
};
typedef cTestClass<VALUE0> cClassVal0; //(1)
typedef cTestClass<VALUE1> cClassVal1; //(2)
typedef cTestClass<VALUE2> cClassVal2; //(3)
//Later in the code
template<int Value>
cTestClass<Value>* Create()
{
return new cTestClass<Value>(/*..*/);
}
//And using the upper function
cClassVal2* pTestClass = Create<VALUE2>();
This works absolutely fine. The goal is to provide a way for users of an interface not to deal with templates and template parameters (Ok, besides using Create()). That is the reason for the typedefs at the bottom of the code.
No here is what I want to achieve next:
cTestClass should have one member variable which is accessible via member functions. Under certain circumstances I either want the user being able to modify the member variable or not to modify the member variable. So basically this means two member functions, one that returns the member as const reference (not modifyable) or non const (modifyable). Problem is, if both those member functions are provided, the user always has the chance to modify the member variable. So I want to choose the appropriate member function during compile time and just provide one correct member function for the user.
The only solution I came up with looks basically like this:
template<int Value, bool ConstAccess>
class cTestClass;
//specializations
template<>
class cTestClass<VALUE0, true>
{
const std::string& get() const
{
return m_strName;
}
static int GetVal() { return VALUE0; }
private:
std::string m_strName;
};
template<>
class cTestClass<VALUE0, false>
{
std::string& get()
{
return m_strName;
}
static int GetVal() { return VALUE0; }
private:
std::string m_strName;
};
//For every upcoming cTestClass two specializations
typedef cTestClass<VALUE0, true> cConstObjectVal0;
typedef cTestClass<VALUE0, false> cObjectVal0;
//And for the rest...
Besides the fact that this really seams to be unnecessary code duplication I always have to specify two typedefs for every possible VALUE. But the user should not be confronted with that choice, he should always be able to just use the types as given above (see 1, 2, 3).
Is this even possible?
I googled a bit and came up with the following site: ACCU:: An introduction to C++ traits.
This explanation seems to a matching blueprint, but I really can't put the pieces together.
Another possibility I found is described here: C++ Template specialization to provide extra member function? Just adding one function would be possible, but this still doesn't solve my typedef problem.
We can try to employ SFINAE:
typedef char True;
typedef long False;
template <typename VALUE0, typename IsConst>
class cTestClass
{
public:
template <typename T, T> struct TypeCheck {};
const std::string& get(TypeCheck<IsConst, True >* dummy = NULL);
std::string& get(TypeCheck<IsConst, False>* dummy = NULL);
}
typedef cTestClass<VALUE0, True> cConstObjectVal0;
typedef cTestClass<VALUE0, False> cObjectVal0;
I didn't try to compile it yet, but the general principle is to prevent one of the functions to compile properly, then, due to the SFINAE principle, the compiler will just throw away the wrong version.
Is there a way to make a templated C++ function implicitly convert all pointers to a void*? I'm working on a lightweight Lua binding and I'd like to avoid writing the exact same function for every pointer type when the void* version is all I need.
Declaration:
template<class T>
T GetFromStack(lua_State* L, int index);
Definition:
template<> void* GetFromStack<void*>(lua_State* L, int index)
{
return lua_touserdata(L, index);
}
If I was to call myVariable = GetFromStack<MyStruct*>(L, 0);, the C++ compiler would complain that I haven't defined a function for a MyStruct*. Is it possible to have every pointer type matched to the void* version implicitly?
EDIT:
I see how my question is a bit confusing, I'm not really sure how to word it. I'm attempting to come up with an automatic binding system. This GetFromStack function is called from another templated function:
template<class T_return, class T_param1, class T_param2 >
int LuaFunction(lua_State* L, T_return (*func)(T_param1,T_param2));
which is implemented like this:
template<class T_return, class T_param1, class T_param2 >
int LuaFunction(lua_State* L, T_return (*func)(T_param1,T_param2))
{
T_param1 a = GetFromStack<T_param1>(L, 1);
T_param2 b = GetFromStack<T_param2>(L, 2);
T_return ret = func(a,b);
PushLuaType(L, ret); // <-- This is another templated function
// like GetFromStack that has the same problem
return 1;
}
I then create a Lua version of whatever function I want to expose to Lua with a simple macro:
#define DeclareLuaFunction(function) \
static int ##function##_lua_(lua_State* L) \
{ \
return LuaFunction(L, function); \
}
This works really well so long as I use the predefined types. I have versions of GetFromStack written for all the "basic" types (int, float, etc) and obviously void*. But I don't want to have to write one for every one of my custom type's pointers. When I create a function that uses a MyStruct2, I'd have to write yet another version of GetFromStack that's identical to every other pointer version.
This system would be used like this:
struct MyStruct
{
int a;
float b;
};
int AddToMyStruct(MyStruct* s, int x)
{
int original = s->a;
s->a += x;
return original;
}
DeclareLuaFunction(AddToMyStruct);
Which would then have T_return as an int, T_param1 as a MyStruct* and T_param2 as an integer too. I already have int versions of GetFromStack and PushLuaType, but I don't have MyStruct* versions. With the way it's implemented now, I'd have to write a new version of GetFromStack for every type I come up with, even though every implementation would be the same.
EDIT: Andreas' solution would work if theres a way I can determine if a type is a pointer or not at compile type. If my T_param1 is a MyStruct*, it will be passed as such to GetFromStack, instead of as a MyStruct.
If I understand it correctly, you need to implement the function differently for different types, but the implementation happens to be the same for all pointer types.
If the value was passed as a parameter, you'd use normal function overloading. In this case, you can use enable_if.
template<typename T>
typename std::enable_if<std::is_pointer<T>::value, T>::type
GetFromStack(lua_State* L, int index)
{
return lua_touserdata(L, index);
}
Ok, here's a new try based on your additional info. As has been said before, much of this could be done much easier if you opt to use C++11, but this should work in most older compilers as well.
First you need a way to detect whether your template param T is a pointer, you could either use std::is_pointer<> (which is preferable) or define one yourself like:
template <class T>
struct is_pointer
{
enum {value = false};
};
template <class T>
struct is_pointer<T *>
{
enum {value = true};
};
template <class T>
struct is_pointer<const T *>
{
enum {value = true};
};
Next you need to alter your implementation based on it. To do that we introduce a helper class (or struct as I'm too lazy to write public) which has several specializations, one for each ordinary type and one for pointers:
template <bool ispointer, class T>
struct GetFromStackHelper;
template <>
struct GetFromStackHelper<false, int>
{
static int GetFromStackFun(lua_State *l, int index)
{
return lua_tointeger(l, index);
}
};
// ... add the rest of the built in types here
template <class T>
struct GetFromStackHelper<true, T>
{
static T GetFromStackFun(lua_State *l, int index)
{
return static_cast<T>(lua_touserdata(l, index));
}
};
Finally we tie it together with the GetFromStack function, which now should not have any specializations:
template <class T>
T GetFromStack(lua_State *l, int index)
{
return GetFromStackHelper<is_pointer<T>::value, T>::GetFromStackFun(l, index);
}
Which you could use as:
int i = GetFromStack<int>(luaState, 6);
MyStruct *p = GetFromStack<MyStruct *>(luaState, 5);
I'm not quite sure if this is what you're looking for, but...
How about passing function pointers?
Your compiler's probably going to give you a bunch of warnings, but it should work.
void *GetFromStack(void *p, int index, void * (*func)(void *, int)) {
return func(p, index);
}
void * (*func)(void *, int) is a function pointer to one that takes a void pointer and an int and returns a void pointer, which you supply as the first 2 parameters to GetFromStack. Just use the reference operator & to get a function pointer for the function you want it to call.
I am currently doing the following to generate a value at compile time, which works:
//if B is true, m_value = TRUEVAL, else FALSEVAL, T is the value type
template<bool B, class T, T TRUEVAL, T FALSEVAL>
struct ConditionalValue
{
typedef T Type;
Type m_value;
ConditionalValue():
m_value(TRUEVAL)
{}
};
template<class T, T TRUEVAL, T FALSEVAL>
struct ConditionalValue<false, T, TRUEVAL, FALSEVAL>
{
typedef T Type;
Type m_value;
ConditionalValue():
m_value(FALSEVAL)
{}
};
Then you can simply do something like this:
template<class T>
void loadPixels(uint32 _w, uint32 _h, T * _pixels)
{
PixelDataType::Type pixelType = PixelDataType::Auto; //enum I want to set
ConditionalValue<boost::is_same<T, uint8>::value, PixelDataType::Type, PixelDataType::UInt8, PixelDataType::Auto> checker;
pixelType = checker.m_value;
ConditionalValue<boost::is_same<T, uint16>::value, PixelDataType::Type, PixelDataType::UInt16, PixelDataType::Auto> checker2;
pixelType = checker2.m_value;
...
}
I know this example does not make much sense, but I use that code to set the value of an enum at compile time.- So here is my question: Is there something like that in std/boost type traits allready? When browsing through the reference I only found conditional which does almost what I want, but only generates a type, not a value.
EDIT:
Updated example.
Edit2:
I just realized that boost::is_same::value is all I need to solve my problem.- As for the answer to the question: There does not seem to be anything included in std/boost for good reason as pointed out by thiton
EDIT3:
If you are still looking for a solution to create a value at compile time, you can either use my code wich works. If you are looking for something very close to boost/stl Kerrek's or Nawaz seem to be valid solutions too. If you are looking for a solution that assigns the correct enum at compile time Luc Touraille approach seems to be interesting even though i decided it's overkill for my situation!
A combination of std::conditional and std::integral_constant might work in some situations:
template <bool B, typename T, T trueval, T falseval>
struct conditional_val : std::conditional<B,
std::integral_constant<T, trueval>,
std::integral_constant<T, falseval>>::type
{ };
Now use:
const int q = conditional_val<B, int, 12, -8>::value;
Equivalently:
const int q = B ? 12 : -8;
I think it's the simple answer: Because the operator ?: can select values quite well. Types are harder to select, that's why boost constructs exist for that. For pathological cases, the boost::mpl magic Luc suggested is fine, but it should be quite rare.
Boost.MPL has a set of classes to manipulate data types at compile-time, along with some arithmetic operations. These classes wrap a value into a type, for instance the integer 4 can be represented by the type mpl::int_<4>.
You can use these in compile-time conditional:
typedef typename
mpl::if_<
boost::is_same< T, uint8 >,
mpl::int_< 42 >,
mpl::int_< 187 >
>::type result;
int i = result::value;
MPL also provides a generic integral wrapper that you can use with your enums:
template<class T>
void loadPixels(uint32 _w, uint32 _h, T * _pixels)
{
PixelDataType::Type pixelType = PixelDataType::Auto; //enum I want to set
typedef typename mpl::if_<
boost::is_same<T, uint8>,
mpl::integral_c<PixelDataType::Type, PixelDataType::UInt8>,
mpl::integral_c<PixelDataType::Type, PixelDataType::Auto>
>::type checker;
pixelType = checker::value;
typedef typename mpl::if_<
boost::is_same<T, uint16>,
mpl::integral_c<PixelDataType::Type, PixelDataType::UInt16>,
mpl::integral_c<PixelDataType::Type, PixelDataType::Auto>
>::type checker2;
pixelType = checker2::value;
...
}
If you have a lot of mapping like this to do, you could consider using a mixed compile-time/runtime data structure such as fusion::map, but that is probably a bit overkill :):
typedef fusion::map<
fusion::pair<uint8, PixelDataType::Type>,
fusion::pair<uint16, PixelDataType::Type> >
map_type;
map_type pixelTypesMap(
make_pair<uint8>(PixelDataType::UInt8),
make_pair<uint16>(PixelDataType::UInt16));
...
template<class T>
void loadPixels(uint32 _w, uint32 _h, T * _pixels)
{
// need special handling if T is not in the map
PixelDataType::Type pixelType = fusion::at_key<T>(pixelTypesMap);
...
}
You can write yourself:
namespace extend
{
template<bool B, class T, T X, T Y>
struct conditional
{
static const T value = X;
};
template<class T, T X, T Y>
struct conditional<false,T,X,Y>
{
static const T value = Y;
};
}
//test
assert(conditional<std::is_same<int,int>::value, int, 10, 20>::value == 10);
assert(conditional<std::is_same<int,char>::value, int, 10, 20>::value == 20);
I came across a case where I needed to do exactly what ? does (compare values, return values) but using template specialization (why would you ever need that? simple: compile time evaluation of ? can lead to "unreachable code" warnings)
So the most standard solution which works for your original question as well as for mine imho is:
std::conditional<myval,
std::integral_constant<T, val>,
std::integral_constant<T, val>
>::type::value;
Now simply replace "myval" with std::is_same and you have a solution for your case (compare types, return values), while above is a solution for my case (compare values, return values <=> ?)
I just started playing with metaprogramming and I am working on different tasks just to explore the domain. One of these was to generate a unique integer and map it to type, like below:
int myInt = TypeInt<AClass>::value;
Where value should be a compile time constant, which in turn may be used further in meta programs.
I want to know if this is at all possible, and in that case how. Because although I have learned much about exploring this subject I still have failed to come up with an answer.
(P.S. A yes/no answer is much more gratifying than a c++ solution that doesn't use metaprogramming, as this is the domain that I am exploring)
In principle, this is possible, although the solution probably isn't what you're looking for.
In short, you need to provide an explicit mapping from the types to the integer values, with one entry for each possible type:
template< typename T >
struct type2int
{
// enum { result = 0 }; // do this if you want a fallback value
};
template<> struct type2int<AClass> { enum { result = 1 }; };
template<> struct type2int<BClass> { enum { result = 2 }; };
template<> struct type2int<CClass> { enum { result = 3 }; };
const int i = type2int<T>::result;
If you don't supply the fallback implementation in the base template, this will fail for unknown types if T, otherwise it would return the fallback value.
Depending on your context, there might be other possibilities, too. For example, you could define those numbers within within the types themselves:
class AClass {
public:
enum { inta_val = 1 };
// ...
};
class BClass {
public:
enum { inta_val = 2 };
// ...
};
// ...
template< typename T >
struct type2int
{
enum { result = T::int_val }; // will fail for types without int_val
};
If you give more context, there might be other solutions, too.
Edit:
Actually there isn't any more context to it. I was looking into if it actually was possible, but without assigning the numbers itself.
I think Mike's idea of ordering is a good way to do this (again, for a fixed set of types) without having to explicitly assign numbers: they're implicitly given by the ordering. However, I think that this would be easier by using a type list. The index of any type in the list would be its number. I think something like the following might do:
// basic type list manipulation stuff
template< typename T1, typename T2, typename T3...>
struct type_list;
// meta function, List is assumed to be some instance of type_list
template< typename T, class List >
struct index_of {
enum { result = /* find index of T in List */ };
};
// the list of types you support
typedef type_list<AClass, BClass, CClass> the_type_list;
// your meta function
template< typename T >
struct type2int
{
enum { result = index_of<T, the_type_list>::result };
};
This does what you want. Values are assigned on need. It takes advantage of the way statics in functions are assigned.
inline size_t next_value()
{
static size_t id = 0;
size_t result = id;
++id;
return result;
}
/** Returns a small value which identifies the type.
Multiple calls with the same type return the same value. */
template <typename T>
size_t get_unique_int()
{
static size_t id = next_value();
return id;
}
It's not template metaprogramming on steroids but I count that as a good thing (believe me!)
Similiar to Michael Anderson's approach but this implementation is fully standards compliant and can be performed at compile time. Beginning with C++17 it looks like constexpr values will be allowed to be used as a template parameter for other template meta programming purposes. Also unique_id_type can be compared with ==, !=, >, <, etc. for sorting purposes.
// the type used to uniquely identify a list of template types
typedef void (*unique_id_type)();
// each instantiation of this template has its own static dummy function. The
// address of this function is used to uniquely identify the list of types
template <typename... Arguments>
struct IdGen {
static constexpr inline unique_id_type get_unique_id()
{
return &IdGen::dummy;
}
private:
static void dummy(){};
};
The closest I've come so far is being able to keep a list of types while tracking the distance back to the base (giving a unique value). Note the "position" here will be unique to your type if you track things correctly (see the main for the example)
template <class Prev, class This>
class TypeList
{
public:
enum
{
position = (Prev::position) + 1,
};
};
template <>
class TypeList<void, void>
{
public:
enum
{
position = 0,
};
};
#include <iostream>
int main()
{
typedef TypeList< void, void> base; // base
typedef TypeList< base, double> t2; // position is unique id for double
typedef TypeList< t2, char > t3; // position is unique id for char
std::cout << "T1 Posn: " << base::position << std::endl;
std::cout << "T2 Posn: " << t2::position << std::endl;
std::cout << "T3 Posn: " << t3::position << std::endl;
}
This works, but naturally I'd like to not have to specify a "prev" type somehow. Preferably figuring out a way to track this automatically. Maybe I'll play with it some more to see if it's possible. Definitely an interesting/fun puzzle.
I think it is possible to do it for a fixed set of types, but quite a bit of work. You'll need to define a specialisation for each type, but it should be possible to use compile-time asserts to check for uniqueness. I'll assume a STATIC_ASSERT(const_expr), like the one in Boost.StaticAssert, that causes a compilation failure if the expression is false.
Suppose we have a set of types that we want unique IDs for - just 3 for this example:
class TypeA;
class TypeB;
typedef int TypeC;
We'll want a way to compare types:
template <typename T, typename U> struct SameType
{
const bool value = false;
};
template <typename T> struct SameType<T,T>
{
const bool value = true;
};
Now, we define an ordering of all the types we want to enumerate:
template <typename T> struct Ordering {};
template <> struct Ordering<void>
{
typedef TypeC prev;
typedef TypeA next;
};
template <> struct Ordering<TypeA>
{
typedef void prev;
typedef TypeB next;
};
template <> struct Ordering<TypeB>
{
typedef TypeA prev;
typedef TypeC next;
};
template <> struct Ordering<TypeC>
{
typedef TypeB prev;
typedef void next;
};
Now we can define the unique ID:
template <typename T> struct TypeInt
{
STATIC_ASSERT(SameType<Ordering<T>::prev::next, T>::value);
static int value = TypeInt<T>::prev::value + 1;
};
template <> struct TypeInt<void>
{
static int value = 0;
};
NOTE: I haven't tried compiling any of this. It may need typename adding in a few places, and it may not work at all.
You can't hope to map all possible types to an integer field, because there are an unbounded number of them: pointer types with arbitrary levels of indirection, array types of arbitrary size and rank, function types with arbitrary numbers of arguments, and so on.
I'm not aware of a way to map a compile-time constant integer to a type, but I can give you the next best thing. This example demonstrates a way to generate a unique identifier for a type which - while it is not an integral constant expression - will generally be evaluated at compile time. It's also potentially useful if you need a mapping between a type and a unique non-type template argument.
struct Dummy
{
};
template<typename>
struct TypeDummy
{
static const Dummy value;
};
template<typename T>
const Dummy TypeDummy<T>::value = Dummy();
typedef const Dummy* TypeId;
template<typename T, TypeId p = &TypeDummy<T>::value>
struct TypePtr
{
static const TypeId value;
};
template<typename T, TypeId p>
const TypeId TypePtr<T, p>::value = p;
struct A{};
struct B{};
const TypeId typeA = TypePtr<A>::value;
const TypeId typeB = TypePtr<B>::value;
I developed this as a workaround for performance issues with ordering types using typeid(A) == typeid(B), which a certain compiler fails to evaluate at compile time. It's also useful to be able to store TypeId values for comparison at runtime: e.g. someType == TypePtr<A>::value
This may be doing some "bad things" and probably violates the standard in some subtle ways... but thought I'd share anyway .. maybe some one else can sanitise it into something 100% legal? But it seems to work on my compiler.
The logic is this .. construct a static member function for each type you're interested in and take its address. Then convert that address to an int. The bits that are a bit suspect are : 1) the function ptr to int conversion. and 2) I'm not sure the standard guarantees that the addresses of the static member functions will all correctly merge for uses in different compilation units.
typedef void(*fnptr)(void);
union converter
{
fnptr f;
int i;
};
template<typename T>
struct TypeInt
{
static void dummy() {}
static int value() { converter c; c.f = dummy; return c.i; }
};
int main()
{
std::cout<< TypeInt<int>::value() << std::endl;
std::cout<< TypeInt<unsigned int>::value() << std::endl;
std::cout<< TypeInt< TypeVoidP<int> >::value() << std::endl;
}
I don't think it's possible without assigning the numbers yourself or having a single file know about all the types. And even then you will run into trouble with template classes. Do you have to assign the number for each possible instantiation of the class?
type2int as compile time constant is impossible even in C++11. Maybe some rich guy should promise a reward for the anwser? Until then I'm using the following solution, which is basically equal to Matthew Herrmann's:
class type2intbase {
template <typename T>
friend struct type2int;
static const int next() {
static int id = 0; return id++;
}
};
template <typename T>
struct type2int {
static const int value() {
static const int id = type2intbase::next(); return id;
}
};
Note also
template <typename T>
struct type2ptr {
static const void* const value() {
return typeid(T).name();
}
};