编写用于检测 Eigen 中的矩阵表达式的类型特征

Posted

技术标签:

【中文标题】编写用于检测 Eigen 中的矩阵表达式的类型特征【英文标题】:Writing a type trait for detecting Matrix Expressions in Eigen 【发布时间】:2016-10-27 19:47:24 【问题描述】:

我正在尝试(但失败)编写检测 Eigen 表达式的类型特征。换句话说,我希望能够检测到A * A + B 等,其中ABEigen 矩阵/向量。目前我正在这样做:

template<typename T>
struct is_matrix_expression : std::false_type

;

template<typename Derived> // specialization
struct is_matrix_expression<Eigen::MatrixBase<Derived>> :
        std::true_type

;

请注意,Eigen::MatrixBase&lt;Derived&gt; 是所有可能的 Eigen 表达式(例如 decltype(A * A + B) 等)的(模板)基础。但是,通用模板正在被挑选出来,因为它更适合decltype(A * A + B) 之类的东西,而不是MatrixBase&lt;Derived&gt; 专业化。

我怎样才能以某种方式强制选择专业化?或者,换句话说,为Eigen::MatrixBase&lt;Derived&gt; 的所有可能的孩子启用专业化?我在std::is_base_of 上玩了一点SFINAE,但这需要一个显式类型而不是一个模板,其中表达式的类型(在本例中为Derived)是事先不知道的。

同样,对于某些类型T,我如何检测类型X 是否是Base&lt;T&gt; 的子类型?

【问题讨论】:

删除typename。你写typename std::template vector&lt;int&gt;吗? this old answer 有用吗? 我认为你的问题是 decltype(A * A + B) 不是 MatrixBase&lt;T&gt;... 它会像 CwiseBinaryOp&lt;X,Y,Z&gt; 对吗? @Barry 是的,它是MatrixBase&lt;...&gt; 的孩子。 @T.C.,抱歉,错字,已更正。 【参考方案1】:

这会检测某些东西是否继承自 bob_template&lt;T&gt;

template<class T>
struct bob_template ;

template<class T>
constexpr std::true_type is_bob_f( bob_template<T> const& )  return ; 

namespace details 
    template<template<class...>class Z, class, class...Ts>
    struct can_apply:std::false_type;
    template<template<class...>class Z, class...Ts>
    struct can_apply<Z, std::void_t<Z<Ts...>>, Ts...>:std::true_type;

template<template<class...>class Z, class...Ts>
using can_apply = details::can_apply<Z, void, Ts...>;

template<class T>
using is_bob_r = decltype( is_bob_f( std::declval<T const&>() ) );

template<class T>
using is_bob = can_apply< is_bob_r, T >;

live example.

C++20 有is_detected,类似于上面的can_apply

std::void_t 是 C++14,但在 C++11 中很容易编写。

用英文阅读以上内容:

is_bob&lt;T&gt; 为真当且仅当您可以调用 is_bob_r&lt;T&gt;

如果is_bob_f( T const&amp; ) 是有效调用,则可以调用is_bob_r

is_bob_f 仅对 is_bob_f( bob_template&lt;T&gt; const&amp; ) 有重载。

如果Z&lt;T&gt; 有效,can_apply&lt;Z, T&gt; 是(派生自)true_type,否则(派生自)false_type

所以is_bob&lt;T&gt; 为真当且仅当对于某些U 可以将T 推导出为bob_template&lt;U&gt;。这基本上意味着bob_template&lt;U&gt;T 的(公共)基类。

【讨论】:

这非常好和通用!【参考方案2】:

这里应该这样做:

template<typename Derived>
struct is_matrix_expression
 : std::is_base_of<Eigen::MatrixBase<std::decay_t<Derived> >, std::decay_t<Derived> >
;

以下代码显示为 true:

Eigen::MatrixXd A, B;
std::cout<< is_matrix_expression <decltype(A*A + B)>::value <<std::endl;   //true
std::cout<< is_matrix_expression <int>::value <<std::endl;                 //false

想法是在这里你知道基类是什么样子的:即,对于SomeMatrixXpr,根据Eigen class hierarchy,它将是MatrixBase&lt;SomeMatrixXpr&gt;。这与@Yakk 的方法形成对比,后者适用于任何类型的基类(甚至那些与 CRTP 无关的基类)。

【讨论】:

这个也可以! @vsoftco:谢谢,我编辑了why 我认为您缺少typename?但实际上你应该把::typeis_base_of 的末尾刮掉;继承就够了。 @Yakk:是的,你是对的......在 MSVC 上测试了它,typenames 非常草率。 @Yakk typename 哪里不见了?看不出有什么问题(即使在编辑中也没有),decay_t 不需要typename(与decay&lt;&gt;::type 相反,是吗?

以上是关于编写用于检测 Eigen 中的矩阵表达式的类型特征的主要内容,如果未能解决你的问题,请参考以下文章

将固定大小的特征矩阵作为参数传递给调用动态大小矩阵的函数

将特征矩阵转换为无符号字符 *

将行优先数组映射到列优先特征矩阵

如何编写以特征张量为参数的通用模板函数?

在 Eigen 中乘以对角矩阵(作为向量提供)

使用 Eigen3 的稀疏矩阵的特征值