C++ 检查类型是否为特征3类型 Eigen3和内置型互兼容性

C++ 检查类型是否为特征3类型 Eigen3和内置型互兼容性,c++,templates,eigen3,C++,Templates,Eigen3,大家好。我一直忙于编写既能处理特征3类型(矩阵和数组)又能处理内置类型的例程。我可以用一个例子来最好地解释这一点:假设我有一个Meter模板类,它能够在运行时收集统计数据 Type类应支持以下运算符: 运算符=(标量) 运算符=(类型) operator+(类型) 运算符-(类型) 运算符*(类型) 运算符/(类型) 运算符*(标量) 运算符/(标量) Eigen3types为所有这些运算符提供了两个例外:首先,如果Type是Eigen::MatrixBase的某个子类,则运算符*(Type

大家好。我一直忙于编写既能处理特征3类型(矩阵和数组)又能处理内置类型的例程。我可以用一个例子来最好地解释这一点:假设我有一个
Meter
模板类,它能够在运行时收集统计数据

Type类应支持以下运算符:

  • 运算符=(标量)
  • 运算符=(类型)
  • operator+(类型)
  • 运算符-(类型)
  • 运算符*(类型)
  • 运算符/(类型)
  • 运算符*(标量)
  • 运算符/(标量)
Eigen3
types为所有这些运算符提供了两个例外:首先,如果
Type
Eigen::MatrixBase
的某个子类,则
运算符*(Type)
表示点积;如果
Type
Eigen::ArrayBase
的某个子类,则表示系数积。我可以很容易地解决这个问题;其次,两者都没有实现确保正确初始化为零所需的
运算符=(标量)

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

用于处理内置类型和
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;
};
表示
0
不能隐式转换为
Eigen::Matrix
,这意味着它选择了函子的
set\u const\u impl
版本(其中两个参数共享一个公共类型
Scalar
)。这也意味着我的
is_scalar
构造在这种情况下不起作用,即使我已经使用了它,并且在其他类上测试过它,也没有问题

我在其他几个类中需要这种行为,我不想显式地专门化它们中的每一个!有人知道我该怎么做才能解决这个问题吗


提前感谢您的帮助

你的问题在于你的traits
是标量的,它只接受基类而不接受派生类

您可以尝试以下方法:

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*>()))
{};
名称空间帮助器
{
模板std::false_类型为_标量(常数特征::矩阵基*);
模板std::false_类型是_标量(const-Eigen::ArrayBase*);
std::true_类型是_标量(…);
}
模板
结构是标量:decltype(Helper::是标量(std::declval())
{};
@Jarod42

谢谢,您的建议带来了一些启发,但我发现了另一个我认为非常可靠的选项:我在命名空间
std::\uu 1
中发现了
is\u scalar
的实现。现在我的代码是

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;
};
templatestruct is\u scalar;
模板<类类型>
结构是\u标量:真\u类型{
使用标量=类型;
};
模板<类类型>
结构是\u标量:false\u类型{
使用Scalar=typename Type::Scalar;
};
我能够正确地区分内置类型和固有类型!无论如何谢谢你

编辑:

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

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

我说的对吗?

我遇到了同样的问题,并试图用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));
模板
constexpr bool是特征型(const-EigenBase*){
返回true;
}
constexpr bool是特征型(const void*){
返回false;
}
模板
constexpr bool is_eigen_type=is_eigen_type_f(重新解释强制转换(NULL));

我强烈建议不要直接使用std::\u 1名称空间中的任何内容。它是特定于libc++的,不打算直接使用。
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*>()))
{};
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;
};
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));