Собственный шаблон по скалярному типу - PullRequest
1 голос
/ 19 октября 2019

Я работаю над кодом с большим количеством классов, которые шаблонируют для скалярного типа T и реализую методы для контейнеров, таких как std::valarray<T>. Я бы хотел добавить поддержку для Eigen-контейнеров, но у меня возникли проблемы с поиском способа создания шаблонов только для скалярного типа при сохранении некоторой гибкости Eigen.

Например, документы Eigen предлагает использовать Eigen::DenseBase<Derived>, но, похоже, это означает, что мне придется изменить все определения моего класса на шаблон для типа массива Derived, а затем использовать Derived::Scalar везде. Довольно навязчиво просто для поддержки другого контейнера.

Я мог бы также просто использовать Matrix<T,Dynamic,Dynamic>, но это довольно ограничительно. В тех случаях, которые меня волнуют, я подумал, что разумным промежуточным вариантом будет использование Ref<Matrix<T,Dynamic,Dynamic>>, поскольку оно будет охватывать Matrix и его фрагменты с одним интерфейсом. Но это, похоже, не работает, и я не уверен, почему. Вот конкретный пример того, что я имею в виду:

#include<iostream>
#include<Eigen/Dense>

using namespace std;
using namespace Eigen;

double
sum1(const Ref<const Matrix<double,Dynamic,Dynamic>> &m)
{
    double x = 0.0;
    for (int j=0; j<m.cols(); ++j)
        for (int i=0; i<m.rows(); ++i)
            x += m(i,j);
    return x;
}

template <typename T>
T
sum2(const Ref<const Matrix<T,Dynamic,Dynamic>> &m)
{
    T x = 0.0;
    for (int j=0; j<m.cols(); ++j)
        for (int i=0; i<m.rows(); ++i)
            x += m(i,j);
    return x;
}

int main()
{
    Matrix<double,Dynamic,Dynamic> a(2,2);
    a << 0,2,1,3;
    cout << "sum1(a) = " << sum1(a) << endl;            // ok
    cout << "sum2(a) = " << sum2(a) << endl;            // error
    cout << "sum2(a) = " << sum2<double>(a) << endl;    // ok
    return 0;
}

Но я получаю ошибки при компиляции:

$ clang++  -std=c++17 -I/usr/include/eigen3   eig2.cpp   -o eig2
eig2.cpp:33:29: error: no matching function for call to 'sum2'
    cout << "sum2(a) = " << sum2(a) << endl;            // error
                            ^~~~
eig2.cpp:19:1: note: candidate template ignored: could not match 'Ref' against
      'Matrix'
sum2(const Ref<const Matrix<T,Dynamic,Dynamic>> &m)
^
1 error generated.

Есть ли способ реализовать sum2, чтобы он поддерживал Matrix и Ref и не требует явных аргументов шаблона для его использования?

1 Ответ

2 голосов
/ 19 октября 2019

Причина, по которой

template <typename T>
T
sum2(const Ref<const Matrix<T,Dynamic,Dynamic>> &m)

не работает для Matrix<T,Dynamic,Dynamic>, заключается в том, что C ++ не может выводить аргументы шаблона и одновременно выполнять преобразование типов (Ref отличается от типа Matrix, но его можно построить с усилием O (1).

Одна альтернатива (требующая C ++ 11 или выше), которая позволяет сохранить тело функции:

template<typename Derived, typename T=typename Derived::Scalar>
T sum3(const MatrixBase<Derived> &m) 

Если вы также хотите разрешить Array, вы можете использовать DenseBase, если вы хотите разрешить разреженные матрицы, вы можете использовать EigenBase.

Однако это не эквивалентноRef реализация с явной подстановкой типов, поскольку, если Derived является выражением, оно может вычисляться несколько раз внутри вашей функции.

Альтернативой является запись

template <typename T>
T
sum_impl(const Ref<const Matrix<T,Dynamic,Dynamic>> &m)
{ /* here comes the actual implementation */ }

template<typename Derived>
typename Derived::Scalar sum4(const Eigen::MatrixBase<Derived>& m)
{
    return sum_impl<typename Derived::Scalar>(m);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...