带有x,y,z的点的模板函数和带有x(),y(),z()的点的模板函数

时间:2014-12-05 19:04:51

标签: c++ templates eigen point-cloud-library

我使用点云工作很多,因此我使用了很多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并正确使用。

2 个答案:

答案 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类型。