编写类型特征以检测 Eigen 中的矩阵表达式
Writing a type trait for detecting Matrix Expressions in Eigen
我正在尝试(但失败了)编写一个检测 Eigen 表达式的类型特征。换句话说,我希望能够检测到 A * A + B
等内容,其中 A
和 B
是 Eigen
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 >;
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 无关的)。
我正在尝试(但失败了)编写一个检测 Eigen 表达式的类型特征。换句话说,我希望能够检测到 A * A + B
等内容,其中 A
和 B
是 Eigen
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 >;
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
.
这里应该做这样的事情:
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 无关的)。