我在 C++ 中遇到了一个真正的大脑灼热者,它以前从未发生在我身上。
问题的要点是,在调用我的(模板)函数时,我定义的默认参数的值被打乱了。只有当我使用默认值调用函数时才会发生这种情况。
我的模板函数声明如下:
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);
}
现在,当我使用默认值 ( transform(vector2<double>(0, 1), view_transform)
) 调用它时,我没有得到我期望的值。使用我看到transform
的 VC++ 调试器z
并w
具有“有趣”的值(根据我的经验,这意味着某些东西没有正确初始化)。
示例有趣的值是:0.0078125000000000000 和 2.104431116947e-317#DEN
现在我试着在 C++ FAQ Lite 上找到答案,用谷歌搜索它;甚至试图用舒伯特让自己平静下来,但我一辈子都想不通。我猜这真的很简单,我怀疑这是某种模板愚蠢的工作。
有没有办法获得我期望和想要的默认值,为什么它对我这样做?
编辑1:
如果我更改调用所以它使用浮点数而不是(transform(vector2<float>(0, 1), view_transform)
)问题就消失了。似乎只有在T
=时才会发生这种情况double
。
编辑2:
只有当我对double
和有两个专业时才会发生这种情况float
。如果我在一个地方使用浮点特化,双重特化会得到奇怪的默认值。如果我更改调用该函数的所有位置,那么它会使用双倍的问题“消失”。我仍然不明白为什么,就像它在设置z
and时使用了错误的偏移或其他东西一样w
。
编辑3:
来自 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);
}
在 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);
}
// ...
如果我运行它,双重专业化的默认参数是正确的,但浮点版本将它的默认参数都设为零(0.000000),虽然更好,但它仍然不是z = 0
和w = 1
.
编辑4:
提出了一个连接问题。