本征分配器导致模板化问题 Class

Eigen Allocator causing Trouble in Templated Class

我有这个class:

typedef vector<Eigen::Affine3d,Eigen::aligned_allocator<Eigen::Affine3d> > VoteList;

template <class T>
class KernelDensityEstimator {

  public:
    KernelDensityEstimator() {}

    void setData(vector<T>& d) {
      data = d;
    }

    void setKernel(double (*k)(T&, T&)) {
      kernel = k;
    }

    double evaluate(T& p) {
      double sum;
      for (int i = 0; i < data.size(); i++) {
        sum += (*kernel)(p, data[i]);
      }
      return sum/data.size();
    }

  private:
    double (*kernel) (T&, T&);
    vector<T> data;

};

我想暂时使用类型为 T = Eigen::Affine3d 的 with。但是,当我调用 setData() 时,它给我带来了麻烦,因为 Eigen 需要为标准容器指定 Eigen::aligend_allocator 以与 Eigen 一起使用。

因此,当我将 vector<Eigen::Affine3d,Eigen::aligned_allocator<Eigen::Affine3d> >(又名 VoteList)作为 setData() 的输入参数时,我的编译器会抱怨:

no known conversion for argument 1 from ‘VoteList {aka std::vector<Eigen::Transform<double, 3, 2>, Eigen::aligned_allocator<Eigen::Transform<double, 3, 2> > >}’ to ‘std::vector<Eigen::Transform<double, 3, 2>, std::allocator<Eigen::Transform<double, 3, 2> > >&’

哪一种说得通,但我认为分配器是对象类型的一部分。有没有办法解决这个问题并保持我的 KernelDensityEstimator 通用?

您基本上希望根据 class 模板参数类型 T 为您的成员 data 使用不同的类型。有几种方法可以做到这一点,这里是一个建议:

  • 为您的 class 定义一个特殊的存储类型,您可以在其中保存数据(最好将其放在合适的命名空间中或在您的 class 中):

    //normal storage type
    template<typename T>
    struct storage_type_impl
    {
        using type = std::vector<T>;
    };
    
    //storage type for Eigen::Transform types
    template<typename ... Args>
    struct storage_type_impl<Eigen::Transform<Args ...> >
    {
        using type = std::vector<Eigen::Transform<Args ...>
                               , Eigen::aligned_allocator<Eigen::Transform<Args ...> > >;
    };
    
    template<typename T>
    using storage_type = typename storage_type_impl<T>::type;
    
  • 现在您可以在 class 中使用它以及模板化的 setData 方法(这就足够了,因为编译器在无法执行数据时仍然会报错 copy/move):

    template <class T>
    struct KernelDensityEstimator
    {
        template<typename D>
        auto setData(D&& d)
        {
            data = std::forward<D>(d);  //calls move assignment if d is an rvalue
                                        //otherwise a copy is performed
        }
        //...
    
    private:
        storage_type<T> data;
        //...
    };    
    

代码未经测试,因为我目前没有可用的 Eigen,但我希望它仍然能够解释基本思想。

您可以为您计划使用的类型启用 Eigen 的 std::vector 特化,详见 there,例如:

#include<Eigen/StdVector>
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Eigen::Affine3d)
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Eigen::Matrix4d)
...