I have hit upon a real brain scorcher in C++, it has never happened to me before.
The gist of the problem is that upon invocation of my (template) function the arguments I have defined defaults for have their values scrambled. It only happens if I call the function with the defaults.
My template function is declared like this:
template <typename T>
vector2<T> transform(vector2<T> const &vec, matrix4<T> const &m, T z = T(0), T w = T(1));
It is later, in the same header, defined like this:
template <typename T>
inline vector2<T> transform(vector2<T> const &vec, matrix4<T> const &m, T z, T w)
{
vector4<T> res = m * vector4<T>(vec.x, vec.y, z, w);
return vector2<T>(res.x, res.y);
}
Now when I call this with defaults (transform(vector2<double>(0, 1), view_transform)
) I don't get the values I expect. Stepping into transform
with VC++s debugger I see z
and w
having "funny" values (which in my experience means something isn't initialized properly).
Example funny values would be: 0.0078125000000000000 and 2.104431116947e-317#DEN
Now I've tried finding the answer on C++ FAQ Lite, googling it; even tried to calm myself with Schubert, but I can't for the life of me figure it out. I'm guessing it's really simple and I suspect it's some kind of template tomfoolery at work.
Is there a way to get the default values I expect and want, and why does it do this to me?
Edit 1:
If I the change call so it uses floats instead (transform(vector2<float>(0, 1), view_transform)
) the problem goes away. It appears this only occurs if T
= double
.
Edit 2:
It only happens if I have two specializations for double
and float
. If I use a float specialization in one place the double specialization gets weird default values. If I change all the places the function is called so it uses double the problems "goes away". I still don't understand why though, it's like it's using faulty offsets or something when setting up z
and w
.
Edit 3:
Tales from the C++ Crypt:
#include <sgt/matrix4.hpp>
int main(int argc, char *argv[])
{
sgt::matrix4<double> m0(
2, 0, 0, 1,
0, 2, 0, 1,
0, 0, 1, 0,
0, 0, 0, 1);
m0 *= m0;
sgt::vector2<double> blah0 = sgt::transform(sgt::vector2<double>(1, 0), m0);
sgt::matrix4<float> m1(
2, 0, 0, 1,
0, 2, 0, 1,
0, 0, 1, 0,
0, 0, 0, 1);
m1 *= m1;
sgt::vector2<float> blah1 = sgt::transform(sgt::vector2<float>(1, 0), m1);
printf("%f", blah0.x);
printf("%f", blah1.x);
}
In matrix4.hpp:
// ...
template <typename T>
vector2<T> transform(vector2<T> const &vec, matrix4<T> const &m, T z = T(0), T w = T(1));
template <typename T>
inline vector2<T> transform(vector2<T> const &vec, matrix4<T> const &m, T z, T w)
{
vector4<T> res = m * vector4<T>(vec.x, vec.y, z, w);
return vector2<T>(res.x, res.y);
}
// ...
If I run that, the double-specialization has it's default arguments correct, but the float version gets both it's default arguments as zero (0.000000) which albeit better, it's still is not z = 0
and w = 1
.
Edit 4:
Made a Connect issue.