您的函数显式返回 Matrix 对象,所以不,它不返回表达式对象。解决此问题的一种方法是让编译器为您推断返回类型(因为表达式对象将是一些巨大的模板化混乱):
template <typename Derived>
auto SampleCov (DenseBase<Derived> const & x) {
auto const x_mean = x.colwise().mean();
return ((x.rowwise() - x_mean).matrix().transpose()
* (x.rowwise() - x_mean).matrix()) / (x.rows() - 1);
}
这是假设您使用的是 C++14 或更高版本。对于仅使用 auto 作为返回类型的 C++11,您需要一个尾随返回类型:
template <typename Derived>
auto SampleCov (DenseBase<Derived> const & x)
-> decltype(((x.rowwise() - x.colwise().mean()).matrix().transpose()
* (x.rowwise() - x.colwise().mean()).matrix()) / (x.rows() - 1)) {
auto const x_mean = x.colwise().mean();
return ((x.rowwise() - x_mean).matrix().transpose()
* (x.rowwise() - x_mean).matrix()) / (x.rows() - 1);
}
请注意,我删除了RowVectorType typedef,因为我没有看到重点。
关于问题 2,我认为上述示例解决了该问题,因为没有更明确命名的类型。返回类型和函数内部的 auto 负责这一点。
最后,问题 3。这取决于您到底想做什么。根据您的说法,上述函数似乎不适用于MatrixXd 对象或调用MatrixXd::block() 返回的对象。
对我来说,这并不表示您需要explicit template instantiation,这就是您要问的。
相反,您可以简单地使SampleCov 的参数类型更通用:
template <typename T>
auto SampleCovGeneric (T const & x) {
auto const x_mean = x.colwise().mean();
return ((x.rowwise() - x_mean).matrix().transpose()
* (x.rowwise() - x_mean).matrix()) / (x.rows() - 1);
}
只要您可以在 T 类型的对象上调用 colwise()、matrix()、...,就可以了。无论如何,这可能是一种更好的方法,因为现在可以将 Eigen 表达式传递给SampleCovGeneric。例如:
Eigen::MatrixXd a(2,2);
// aTranspose is NOT a matrix object!
// Its type is Eigen::Transpose<Eigen::Matrix<double, Dynamic, Dynamic>>.
auto aTranspose = a.transpose();
/* Note use of auto and eval() calls!
* See https://eigen.tuxfamily.org/dox/TopicPitfalls.html.
*/
auto b = SampleCov(aTranspose.eval()).eval();
auto c = SampleCovGeneric(aTranspose).eval();
在上面的例子中,SampleCov 需要一个 DenseBase<Derived> 类型的对象。但是aTranspose不是这样的类型。所以我们必须首先明确评估(即实际计算)转置。根据SampleCov 内部发生的情况,这是一个无用的计算。例如。想象计算的第一件事是它的转置参数 (x)。在这种情况下,那将只是原来的 a 。但是如果转置已经被评估,那么 Eigen 就无法“看到”它,需要计算转置的转置。
另一方面,SampleCovGeneric 接受任何类型,因此无需先评估aTranspose。这(可能)允许 Eigen “看穿”一堆计算,从而以更优化的方式计算结果。参见例如https://eigen.tuxfamily.org/dox/TopicLazyEvaluation.html.
如果你真的需要,你可以explicitly instantiate templates,这样它们就可以被分割成头文件和源文件。会是这样的:
/* Header */
#pragma once
#include <utility>
// Reduce trailing return type mess a little
template <class T>
using SampleCovResultType = decltype(((std::declval<T const &>().rowwise()
- std::declval<T const &>().colwise().mean()).matrix().transpose()
* (std::declval<T const &>().rowwise()
- std::declval<T const &>().colwise().mean()).matrix())
/ (std::declval<T const &>().rows() - 1));
template <typename T>
auto SampleCov (T const & x) -> SampleCovResultType<T>;
// Explicit template declaration
extern template
auto SampleCov<Eigen::MatrixXd> (Eigen::MatrixXd const & x)
-> SampleCovResultType<Eigen::MatrixXd>;
/* Source */
#include "SampleCov.h"
template <class T>
auto SampleCov (T const & x) -> SampleCovResultType<T> {
auto const x_mean = x.colwise().mean();
return ((x.rowwise() - x_mean).matrix().transpose()
* (x.rowwise() - x_mean).matrix()) / (x.rows() - 1);
}
// Explicit template definition
template
auto SampleCov<Eigen::MatrixXd> (Eigen::MatrixXd const & x)
-> SampleCovResultType<Eigen::MatrixXd>;
我认为你不能只使用 auto 作为返回类型。由于函数定义放在单独的源文件中,编译器看不到函数体,所以在调用函数时无法推断返回类型。所以你必须使用尾随返回类型。
请注意以下几点:
显式实例化声明(外部模板)可防止
隐式实例化:否则会导致
隐式实例化必须使用显式实例化
在程序的其他地方提供的定义。
即如果您尝试使用未显式实例化 SampleCov 的类型 T 调用 SampleCov,编译将失败。
注意:以上所有代码均未经测试。拼写错误的可能性很高:)。
编辑: