我使用点云工作很多,因此我使用了很多PCL和Eigen库。 PCL中的积分有.x .y和.z公共成员。 Eigen中的点有.x()。y()和.z()
我经常发现自己为一个点类型编写一个函数,然后通过创建一个临时点从一种类型转换为另一种类型来调用它:
e.g。
void f(const Eigen::Vector3d &p) { ... }
pcl::PointXYZ p;
f(Eigen::Vector3d(p.x, p.y, p.z);
为了使问题进一步复杂化,PCL点有各种类型:XYZ,XYZRGB,XYZN等(参见http://pointclouds.org/documentation/tutorials/adding_custom_ptype.php)和特征向量也有几种类型:Vector3d用于双精度,Vecto3f用于浮点数,两种Matrix类型的特化(参见http://eigen.tuxfamily.org/dox/group__matrixtypedefs.html)
我想知道是否可以调用一些模板特化魔术咒语来避免这种情况,即它会检测点类型是否具有.x()或.x并正确使用。
答案 0 :(得分:1)
为了检测某个类是否具有某个名称的方法或成员变量,您可以使用经典的SFINAE方法:
template<typename T>
class has_x {
private:
typedef char yes[1];
typedef char no[2];
template<typename U> static yes& test_member(decltype(U::x));
template<typename U> static no& test_member(...);
template<typename U, U> struct check;
template<typename U> static yes& test_method(check<float (U::*)(), &U::x>*);
template<typename U> static no& test_method(...);
public:
static const bool as_method = (sizeof(test_method<T>(0)) == sizeof(yes));
static const bool as_member = (sizeof(test_member<T>(0)) == sizeof(yes));
};
可在一个小型测试套件中测试:
struct something_else {
};
struct fn_vec {
float x() const { return 66; };
};
struct mem_vec {
mem_vec() : x(55) {};
float x;
};
int main(int argc, char*argv[]) {
std::cout << "fv: " << has_x<fn_vec>::as_method << std::endl;
std::cout << "mv: " << has_x<mem_vec>::as_method << std::endl;
std::cout << "se: " << has_x<something_else>::as_method << std::endl;
std::cout << std::endl;
std::cout << "fv: " << has_x<fn_vec>::as_member << std::endl;
std::cout << "mv: " << has_x<mem_vec>::as_member << std::endl;
std::cout << "se: " << has_x<something_else>::as_member << std::endl;
return 0;
}
输出:
fv: 1
mv: 0
se: 0
fv: 0
mv: 1
se: 0
然后,您可以将其与std::enable_if
一起使用,以编写特定于每种类型的函数或结构的变体。您还可以使用logical operators in std::enable_if
's condition创建所需条件的任意组合。
与上述相同的测试框架中的一个愚蠢的例子:
template<typename T>
typename std::enable_if<has_x<T>::as_method, float>::type getX(const T& v) {
return v.x();
}
template<typename T>
typename std::enable_if<has_x<T>::as_member, float>::type getX(const T& v) {
return v.x;
}
template<typename T>
void foo(const T& val) {
std::cout << getX(val) << std::endl;
}
int main(int argc, char*argv[]) {
fn_vec fn;
mem_vec mem;
foo(fn);
foo(mem);
return 0;
}
输出:
66
55
希望能够为您提供创建通用框架所需的所有工具。因为所有内容都是模板化的,所以大多数都应该被编译器优化掉,并且最终效率相当高。
所有在Linux上的GCC 4.8.2中进行了测试,但它应该适用于任何C ++ 11编译器。
答案 1 :(得分:1)
如果你不想和SFINAE一起玩,你可以在PCL中使用漂亮的内置地图并使用特征投射功能
您可以执行以下操作,而不是构建Eigen::Vector3d
类型并将其传递给f()
,而不是
pcl::PointXYZ p;
f(p.getVector3fMap().cast<double>);
getVector3fMap()
适用于所有内置PCL类型。