Я только начал использовать Eigen и прочитал в их документации, что наилучшая производительность достигается за счет ленивой оценки матричных выражений. Следовательно, такие выражения очень эффективны после вычисления:
Eigen::Matrix<float, 3, 1> a;
a << 0, 1, 2;
Eigen::Matrix<float, 3, 1> b;
b << 3, 4, 5;
Eigen::Matrix<float, 3, 1> c;
c << (a + b).sum(),
(a - b).sum(),
a.sum();
std::cout << c << std::endl;
Я столкнулся с проблемой при построении матриц, количество столбцов которых зависит от параметра шаблона. Например:
template <std::size_t w>
auto buildGradient() {
Eigen::Matrix<float, 3, w> matrix;
matrix << /* ? */;
return matrix;
}
Моим первым желанием было использовать рекурсивный шаблон С++ для этого.
template <std::size_t w, typename Functor>
auto buildGradientExpr(Functor functor) {
if constexpr (w == 0) {
return;
} else if constexpr (w == 1) {
return functor();
} else {
return functor(), buildGradientExpr<w - 1, Functor>(functor);
}
}
Но использование этого приводит к ошибкам времени выполнения, выдаваемым Eigen, поскольку выражение имеет только один инициализатор.
template <std::size_t w>
auto buildGradient() {
Eigen::Matrix<float, 3, w> gradient;
/* Emits an error about too few coefficients being passed to the initializer. */
gradient << buildGradientExpr<w>([]() { /* Return 3x1 matrix */ });
return gradient;
}
Вот полный работающий пример.
#include <Eigen/Dense>
#include <iostream>
#include <cstddef>
namespace {
template <std::size_t w, typename Functor>
auto buildGradientExpr(Functor functor) {
if constexpr (w == 0) {
return;
} else if constexpr (w == 1) {
return functor(w);
} else {
return functor(w), buildGradientExpr<w - 1, Functor>(functor);
}
}
template <std::size_t w, typename Functor>
auto buildGradient(Functor functor) {
Eigen::Matrix<float, 3, w> gradient;
gradient << buildGradientExpr<w>(functor);
return gradient;
}
} // namespace
int main() {
constexpr std::size_t gradient_width = 10;
auto gradient_functor = [](std::size_t w) {
return Eigen::Matrix<float, 3, 1>::Constant(float(w) / gradient_width);
};
auto gradient = buildGradient<gradient_width>(gradient_functor);
std::cout << gradient << std::endl;
return 0;
}
Есть ли способ построить матрицы с размерами, которые зависят от параметров шаблона, не прибегая к циклу for? Ничего против циклов for, это то, что я использую в настоящее время. Я просто хотел бы знать, есть ли способ инициализировать матричное выражение с помощью циклов шаблонов.
Изменить:* я обновил пример, потому что функтор градиента должен был возвращать вектор, а не скаляр. Однако возникает проблема с образцом.
std::initializer_list<std::initializer_list<float> >
(требуется основная ветка Eigen). Хотя не уверен, что это действительно что-то упрощает. - person chtz   schedule 18.03.2020std::initializer_list
равноconstexpr
, начиная с С++ 14. Это кажется хорошим выбором. На самом деле это не было целью упростить что-либо, это означало улучшить оптимизацию времени компиляции для инициализации матрицы. Честно говоря, это, вероятно, преждевременная оптимизация. В любом случае, если вы хотите опубликовать это как ответ, я приму это. - person tay10r   schedule 18.03.2020