首页 文章

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

提问于
浏览
2

我使用点 Cloud 工作很多,所以我使用了很多PCL和Eigen库 . PCL中的积分有.x .y和.z公共成员 . Eigen中的点有.x() . y()和.z()

我经常发现自己为一个点类型编写一个函数,然后通过创建一个临时点从一种类型转换为另一种类型来调用它:

例如

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 回答

  • 1

    如果你不想和SFINAE一起玩,你可以在PCL中使用漂亮的内置 Map 并使用特征投射功能

    您可以执行以下操作,而不是构建 Eigen::Vector3d 类型并将其传递给 f()

    pcl::PointXYZ p;
    f(p.getVector3fMap().cast<double>);
    

    getVector3fMap() 适用于所有内置PCL类型 .

  • 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编译器 .

相关问题