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

Writing a type trait for detecting Matrix Expressions in Eigen

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

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> 是所有可能的特征表达式(例如 decltype(A * A + B) 等)的(模板)基础。然而,通用模板正在被挑选出来,因为它更适合 decltype(A * A + B) 之类的东西,而不是 MatrixBase<Derived> 专业化。

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

同样,对于某些类型 T,我如何检测类型 X 是否是 Base<T> 的子类型?

这会检测是否继承自 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> 为真当且仅当 T 对于某些 U 可以推导为 bob_template<U>。这基本上意味着 bob_template<U>T.

的 (public) 基础 class

这里应该做这样的事情:

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

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