1

Eigen3 和内置类型互兼容

大家好。我遇到了编写可以同时处理 Eigen3 类型(矩阵和数组)和内置类型的例程的问题。我可以用一个例子来最好地解释这一点:假设我有一个Meter<Type>模板类,它能够在运行时收集统计信息。

Type 类应支持以下运算符:

  • operator=(Scalar)
  • operator=(Type)
  • operator+(Type)
  • operator-(Type)
  • operator*(Type)
  • operator/(Type)
  • operator*(Scalar)
  • operator/(Scalar)

Eigen3types 为所有这些运算符提供了两个例外:首先,如果是 的某个子类,则operator*(Type)表示点推导;如果是Type的某个子类,则Eigen::MatrixBase表示系数乘积。我可以很容易地解决这个问题;其次,两者都没有实现确保正确初始化为零的要求。TypeEigen::ArrayBaseoperator=(Scalar)

我尝试实现以下仿函数类来帮助我处理区别,但我无法让它们工作:

一些结构来处理内置类型和Eigen3类型之间的区别:

template < class _Type > struct is_scalar : true_type {
    using Scalar = _Type;
    using Type = _Type;

    static constexpr bool value = true;
};

template < class _Matrix >
struct is_scalar<Eigen::MatrixBase<_Matrix>> : false_type {
    using Scalar = typename Matrix::Scalar;
    static constexpr bool value = false;
};

template < class _Array >
struct is_scalar<Eigen::ArrayBase<_Array>>  : false_type {
    using Scalar = typename Array::Scalar;
    static constexpr bool value = false;
};

函数实现本身

template < class Scalar, bool is_scalar = Math::is_scalar<Scalar>::value > 
struct set_const_impl;

template < class Scalar >
struct set_const_impl< Scalar, true > {
    static const void run(Scalar &_x, Scalar _y) noexcept { _x = _y; }
};

template < class EigenType >
struct set_const_impl<EigenType, false> {
    template < class Scalar >
    static const void run(Eigen::EigenBase<EigenType> &_x, Scalar _y) noexcept {
        _x.derived().setConstant(_y);
    }
};

template < class Type, class Scalar > void set_const(Type &_x, Scalar _y) noexcept {
    set_const_impl<Type>::run(_x, _y);
}

template < class Type > void set_zero(Type &_x) noexcept {
    set_const_impl<Type>::run(_x, 0);
}

专用版本set_const_impl<EigenType>永远不会被实例化。例如,如果我打电话

Eigen::Matrix<double, 3, 1> m1; 
set_zero(m1);

我让编译器0在线投诉

set_const_impl<Type>::run(_x, 0);

说它0不能隐式转换为Eigen::Matrix<double, 3, 1>,这意味着它选择了set_const_impl<Scalar, true>仿函数的版本(其中两个参数共享一个公共类型Scalar)。这也意味着我的is_scalar构造在这种情况下不起作用,即使我已经使用它并在其他类上测试它没有问题。

我在其他几个类中需要这种行为,我不想明确地专门化它们中的每一个!任何人都知道我应该怎么做才能解决这个问题?

提前感谢您的帮助!

4

3 回答 3

1

你的问题是你的特征is_scalar只需要基类而不是派生类。

您可以尝试以下方法:

namespace Helper
{
    template <typename T> std::false_type is_scalar(const Eigen::MatrixBase<T>*);
    template <typename T> std::false_type is_scalar(const Eigen::ArrayBase<T>*);
    std::true_type is_scalar(...);
}

template<typename T>
struct is_scalar : decltype(Helper::is_scalar(std::declval<T*>()))
{};
于 2014-08-09T21:50:34.967 回答
1

我遇到了同样的问题,并试图用 C++17 解决它。这是我的解决方案。

template<typename Derived>
constexpr bool is_eigen_type_f(const EigenBase<Derived> *) {
    return true;
}
constexpr bool is_eigen_type_f(const void *) {
    return false;
}

template<typename T>
constexpr bool is_eigen_type = is_eigen_type_f(reinterpret_cast<T *>(NULL));
于 2018-07-23T06:18:55.237 回答
-1

@Jarod42

谢谢,您的建议带来了一些启示,但我发现了另一个我认为非常可靠的选项:我is_scalar<Type>在 namespace 中找到了一个实现std::__1。现在我的代码读取

template < class Type, bool _is_scalar = std::__1::is_scalar<Type>::value > struct is_scalar;

template < class Type >
struct is_scalar<Type, true> : true_type {
    using Scalar = Type;
};

template < class Type >
struct is_scalar<Type, false> : false_type {
    using Scalar = typename Type::Scalar;
};

而且我能够正确区分内置类型和特征类型!还是非常感谢!

编辑:

通过查看源代码,std::__1::is_scalar我还注意到该解决方案可能代表任何类型的容器对象,只要它提供的类型Scalar

  • 算术类型 OR
  • 成员指针或
  • 一个指针或
  • 空指针或
  • 枚举常数

我对么?

于 2014-08-09T23:39:49.553 回答