编写用于检测 Eigen 中的矩阵表达式的类型特征
Posted
技术标签:
【中文标题】编写用于检测 Eigen 中的矩阵表达式的类型特征【英文标题】:Writing a type trait for detecting Matrix Expressions in Eigen 【发布时间】:2016-10-27 19:47:24 【问题描述】:我正在尝试(但失败)编写检测 Eigen 表达式的类型特征。换句话说,我希望能够检测到A * A + B
等,其中A
和B
是Eigen
矩阵/向量。目前我正在这样做:
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<Derived>
是所有可能的 Eigen 表达式(例如 decltype(A * A + B)
等)的(模板)基础。但是,通用模板正在被挑选出来,因为它更适合decltype(A * A + B)
之类的东西,而不是MatrixBase<Derived>
专业化。
我怎样才能以某种方式强制选择专业化?或者,换句话说,为Eigen::MatrixBase<Derived>
的所有可能的孩子启用专业化?我在std::is_base_of
上玩了一点SFINAE,但这需要一个显式类型而不是一个模板,其中表达式的类型(在本例中为Derived
)是事先不知道的。
同样,对于某些类型T
,我如何检测类型X
是否是Base<T>
的子类型?
【问题讨论】:
删除typename
。你写typename std::template vector<int>
吗?
this old answer 有用吗?
我认为你的问题是 decltype(A * A + B)
不是 MatrixBase<T>
... 它会像 CwiseBinaryOp<X,Y,Z>
对吗?
@Barry 是的,它是MatrixBase<...>
的孩子。
@T.C.,抱歉,错字,已更正。
【参考方案1】:
这会检测某些东西是否继承自 bob_template<T>
:
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<T>
为真当且仅当您可以调用 is_bob_r<T>
。
如果is_bob_f( T const& )
是有效调用,则可以调用is_bob_r
。
is_bob_f
仅对 is_bob_f( bob_template<T> const& )
有重载。
如果Z<T>
有效,can_apply<Z, T>
是(派生自)true_type
,否则(派生自)false_type
。
所以is_bob<T>
为真当且仅当对于某些U
可以将T
推导出为bob_template<U>
。这基本上意味着bob_template<U>
是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<SomeMatrixXpr>
。这与@Yakk 的方法形成对比,后者适用于任何类型的基类(甚至那些与 CRTP 无关的基类)。
【讨论】:
这个也可以! @vsoftco:谢谢,我编辑了why 我认为您缺少typename
?但实际上你应该把::type
从is_base_of
的末尾刮掉;继承就够了。
@Yakk:是的,你是对的......在 MSVC 上测试了它,typename
s 非常草率。
@Yakk typename
哪里不见了?看不出有什么问题(即使在编辑中也没有),decay_t
不需要typename
(与decay<>::type
相反,是吗?以上是关于编写用于检测 Eigen 中的矩阵表达式的类型特征的主要内容,如果未能解决你的问题,请参考以下文章