ColDet是一个非常著名的开源碰撞检测包。我下载之后,使用包中自带的makefile.g++编译它,出现了一些bug:
g++ -c -O2 -DGCC coldet.cpp
In file included from box.h:28:0,
from coldetimpl.h:28,
from coldet.cpp:25:
math3d.h: 在成员函数‘void Matrix3D::rotate(const Vector3D&)’中:
math3d.h:232:44: 错误: ‘PitchMatrix3D’在此作用域中尚未声明
math3d.h:233:44: 错误: ‘YawMatrix3D’在此作用域中尚未声明
math3d.h:234:44: 错误: ‘RollMatrix3D’在此作用域中尚未声明
In file included from coldetimpl.h:28:0,
from coldet.cpp:25:
box.h: 在构造函数‘BoxTreeInnerNode::BoxTreeInnerNode(const Vector3D&, const Vector3D&, int)’中:
box.h:150:38: 错误: ‘NULL’在此作用域中尚未声明
box.h: 在成员函数‘virtual int BoxTreeInnerNode::getSonsNumber()’中:
box.h:165:18: 错误: ‘NULL’在此作用域中尚未声明
box.h:166:19: 错误: ‘NULL’在此作用域中尚未声明
box.h: 在成员函数‘virtual BoxTreeNode* BoxTreeInnerNode::getSon(int)’中:
box.h:177:12: 错误: ‘NULL’在此作用域中尚未声明
box.h: 在成员函数‘virtual BoxTreeNode* BoxedTriangle::getSon(int)’中:
box.h:193:43: 错误: ‘NULL’在此作用域中尚未声明
box.h: 在成员函数‘virtual BoxedTriangle* BoxedTriangle::getTriangle(int)’中:
box.h:198:12: 错误: ‘NULL’在此作用域中尚未声明
coldet.cpp: 在成员函数‘virtual bool CollisionModel3DImpl::collision(CollisionModel3D*, int, int, float*)’中:
coldet.cpp:51:33: 错误: ‘NULL’在此作用域中尚未声明
coldet.cpp: 在成员函数‘virtual bool CollisionModel3DImpl::getCollidingTriangles(float*, float*, bool)’中:
coldet.cpp:310:13: 错误: ‘NULL’在此作用域中尚未声明
coldet.cpp:316:13: 错误: ‘NULL’在此作用域中尚未声明
coldet.cpp:325:13: 错误: ‘NULL’在此作用域中尚未声明
coldet.cpp:331:13: 错误: ‘NULL’在此作用域中尚未声明
make: *** [coldet.o] 错误 1
这个包 历史比较悠久了,包中自带的readme.txt中给出的说明是用g++ 2.8编译。我的gcc版本已经是4.6.3了。奇怪,为什么2.8编译通过的代码,4.6.3 竟然报错呢?
根据错误提示,找到math3d.h中出现PitchMatrix3D的地方,一共有四处。按照从上到下的顺序,第一处出现在struct Matrix3D中:
friend Matrix3D PitchMatrix3D(const float theta);
第二处出现在struct Matrix3D的成员函数的定义中(注意,这里就是第232行,出现关于PitchMatrix3D的错误):
inline void
Matrix3D::rotate(const Vector3D& v)
{
if (v.x!=0.0f) *this = PitchMatrix3D(v.x) * (*this);
if (v.y!=0.0f) *this = YawMatrix3D (v.y) * (*this);
if (v.z!=0.0f) *this = RollMatrix3D (v.z) * (*this);
}
第三处 和第四处就是真正的PitchMatrix3D函数定义了:
inline Matrix3D
PitchMatrix3D(const float c, const float s)
{
return Matrix3D(1.0f, 0.0f, 0.0f, 0.0f,
0.0f, c, -s, 0.0f,
0.0f, s, c, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
}
inline Matrix3D
PitchMatrix3D(const float theta)
{
return PitchMatrix3D((float) cos(theta), (float) sin(theta));
}
PitchMatrix3D在此作用域中尚未声明 的错误让我纠结了很久。很显然,第三处和第四处就是PitchMatrix3D函数定义而已,没有错误。错就错在第二处。众目睽睽之下,struct Matrix3D的定义中明明写清楚了PitchMatrix3D是其友元函数,怎么到了第232行使用它的时候反而翻脸不认人了呢?难道结构体内 声明友元函数,结构体外不能直接使用吗?
说到结构体,很多习惯了c++中class的人们可能感觉别扭。好吧,其实在c++中,结构体和类的唯一区别就是,在默认情况下,类数据成员和成员函数的访问控制是private,结构体数据成员和成员函数的访问控制是public。这里为了方便,不妨就认为PitchMatrix3D是classMatrix3D的友元函数。在网上某些帖子的提示下,我找到了圣经《C++编程语言》的11.5.1节:友元的查找。里面有几句话,我摘抄如下:
“像成员函数一样,一个友元声明不会给外围的作用域引进一个名字。......对于大型程序和大的类,一个类不能‘默不作声地’给它的外围作用域加入一些名字,维持这种性质是非常好的事情。”
茅塞顿开有木有啊亲!《C++编程语言》牛逼至尊啊亲!
我以迅雷不及掩耳盗铃儿响叮当仁不让之势,在PitchMatrix3D作为友元函数出现之前,加上了PitchMatrix3D函数的声明。同样地,加上YawMatrix3D和RollMatrix3D的函数声明。再make,这个让人蛋疼的编译错误就灰飞烟灭了。
当然,还有其他错误,就是提示一大堆“‘NULL’在此作用域中尚未声明”。这个小意思,NULL不是关键字,需要提前定义的。在出错的文件前面加上#include <cstddef>即可。
编译成功之后,得到的最终结果就是一个名为libcoldet.a的库文件。