typedefs are weak
Posted by: Jason Hughes in programming on Jun 18, 2009
So, there's a lot of issues with C++ and the poor support for creating new types. Particularly, it's often useful to make a type-safe integer... for example, if you have several different functions that do similar things and are easy to confuse the values, since an int is an int is an int. It'd be really nice to have the compiler help you when you pass an integer you got from one function into another that means a totally different thing.
Let's get more specific, since all this dancing about is tiresome:
typedef uint32 AxMutexId; typedef uint32 AxSemaphoreId; static void Lock(AxMutexId const mutexId); static int Lock(AxSemaphoreId const semaphoreId);So, this won't compile because the Lock function is ambiguous. Why? Because typedefs make "soft" types, which resolve to whatever they really are and do not really retain their new names to the compiler.
Okay, what about a simple namespace solution?
namespace AxMutex { typedef uint32 Id; }
namespace AxSemaphore { typedef uint32 Id; }
static void Lock(AxMutex::Id const mutexId);
static int Lock(AxSemaphore::Id const semaphoreId);
I'd be okay with this. Except again, it doesn't compile. Finally, I settled on making new types that are actually incompatible with each other, using templates. Such as:
//-------------------
template <typename T, int I>
class IntType
{
public:
IntType(T const value) : mValue(value) {}
operator T & (void) { return mValue; }
operator T const &(void) const { return mValue; }
IntType<T,I> &operator=(T const &rhs) { mValue = rhs; return *this; }
protected:
private:
T mValue;
};
//-------------------
typedef IntType<uint32,0> AxSemaphoreId;
typedef IntType<uint32,1> AxMutexId;
static void Lock(AxMutexId const mutexId);
static int Lock(AxSemaphoreId const semaphoreId);
The nice side effect about this approach is that you can pretty much treat this new type as whatever the POD type it's based on as a drop-in replacement. Warning: some certain code constructs (like the switch statement) may require an explicit cast or .Get() function to be added to get the compiler to sort itself out. But for my specific case where the values are simply indices and not handled mathematically, it works fine. It's been a clean way to create index types that the compiler can treat as a first class citizen, and I thought I'd share.
Is there anything in the new standard, or any simpler method, that accomplishes the same behavior?


