大家好。我遇到了编写可以处理Eigen3类型(Matrixes和Arrays)和内置类型的例程的问题。我可以用一个例子来解释这个:我假设我有一个Meter<Type>
模板类,它能够在运行时收集统计信息。
Type类应支持以下运算符:
operator=(Scalar)
operator=(Type)
operator+(Type)
operator-(Type)
operator*(Type)
operator/(Type)
operator*(Scalar)
operator/(Scalar)
Eigen3
类型为所有这些运算符提供了两个例外:首先,如果operator*(Type)
是Type
的某个子类,则Eigen::MatrixBase
表示点前导并表示系数如果Type
是Eigen::ArrayBase
的某个子类,则为-wise产品。我可以很容易地解决这个问题;第二,两者都没有实现确保正确初始化为零所需的operator=(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
构造在这种情况下不起作用,即使我已经使用它并在其他类上测试它没有问题。
我在其他几个类中需要这种行为,我不想明确地专门化它们中的每一个!任何人都知道我该怎么做才能解决这个问题?
提前感谢您的帮助!
答案 0 :(得分:0)
你的问题是你的特征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*>()))
{};
答案 1 :(得分:0)
@ Jarod42
谢谢你,你的建议带来了一些启示,但我找到了另一个选项,我认为这个选项非常可靠:我在命名空间is_scalar<Type>
中找到了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
我说错了吗?
答案 2 :(得分:0)
我遇到了同样的问题,并尝试使用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));