Careless use of templates can cause bloat. One way to avoid that bloat is to have a thin typesafe template that wraps non-typesafe non-template code. To do this, the wrapper nee
Careless use of templates CAN cause bloat. But you're totally missing the point here.
You just haven't thought this through properly at all. The advantages templates offer far outweigh a few kb in executable size.
It's also worth noting that the code works as expected on Visual Studio 2010.
Did you switch off warnings? You should have got some "dereferencing type punned pointers violates strict aliasing", because thats exactly what you do at (void**) Ptr_Add(...
The compiler is free to assume that pointers to different types do not alias (with a few execpitions), and will produce optimized code which caches the targets of pointers in registers. To avoid that, you have to use unions to convert between different pointers types. Quoting from http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html#Optimize-Options:
In particular, an object of one type is assumed never to reside at the same address as an object of a different type, unless the types are almost the same. For example, an unsigned int can alias an int, but not a void* or a double. A character type may alias any other type.
Pay special attention to code like this:
union a_union { int i; double d; }; int f() { union a_union t; t.d = 3.0; return t.i; }
The practice of reading from a different union member than the one most recently written to (called “type-punning”) is common. Even with -fstrict-aliasing, type-punning is allowed, provided the memory is accessed through the union type. So, the code above will work as expected. See Structures unions enumerations and bit-fields implementation. However, this code might not:
int f() { union a_union t; int* ip; t.d = 3.0; ip = &t.i; return *ip; }
Similarly, access by taking the address, casting the resulting pointer and dereferencing the result has undefined behavior, even if the cast uses a union type, e.g.:
int f() { double d = 3.0; return ((union a_union *) &d)->i; }
The -fstrict-aliasing option is enabled at levels -O2, -O3, -Os.
In your case you could use something like
union {
void** ret_ptr;
ptrdiff_t in_ptr;
}
but the code in ptr_add just looks horrible ;-)
Or just disable this specific optimization with "fno-strict-aliasing". Better fix your code though ;-)