как передать функцию prod () для матрицы повышения в качестве функции умножения? - PullRequest
3 голосов
/ 01 февраля 2012

Я пытаюсь выполнить матричное возведение в степень, но я не хочу копировать / вставлять свою функцию возведения в степень, а скорее использовать шаблоны классов.Проблема в том, что для матриц буста, для умножения матриц, вы используете функцию prod (вместо operator*).

Кажется, g ++ не может определить шаблон, который я хочу использовать.Ошибка, которую я получаю с кодом ниже:

41:37: error: no matching function for call to 'my_pow(boost::numeric::ublas::matrix<int>&, int, <unresolved overloaded function type>)'

вот код:

#include <iostream>
using namespace std;

#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/io.hpp>

typedef long long int64;

template <class T, class M> T my_pow(T b, int64 e, M mult)
{
  if (e == 1) return b;
  if (e % 2 == 1) return mult(b, my_pow(b, e - 1, mult));
  T tmp = my_pow(b, e / 2, mult);
  return mult(tmp, tmp);
}
template <class T> T my_pow(T b, int64 e) { return my_pow(b, e, multiplies<T>()); }

int main()
{
  using namespace boost::numeric::ublas;
  matrix<int> m(3, 3);
  for (unsigned i = 0; i < m.size1(); ++i)
    for (unsigned j = 0; j < m.size2(); ++j)
      m(i, j) = 3 * i + j;
  std::cout << m << std::endl;
  std::cout << my_pow(m, 2, prod) << std::endl;
}

Есть ли способ передать prod () в my_pow, чтобы шаблон разрешился?Спасибо.

В случае, если неясно: b - это основание, e - показатель степени, а my_pow - для вычисления b ^ e

Ответы [ 2 ]

2 голосов
/ 02 февраля 2012

Есть две проблемы.Во-первых, prod является шаблонизированной функцией, поэтому вы не можете просто передать prod в качестве указателя на функцию.Вместо этого вам нужно будет передать prod<...> с заполненными конкретными параметрами шаблона.

Однако в этом случае это все равно не решит вашу проблему, потому что даже с указанными параметрами шаблона prod все еще имеет несколько перегрузок.и компилятор не может определить, какой он должен использовать.Это можно исправить, объявив указатель на функцию, который указывает аргументы и тип возвращаемого значения.Однако, поскольку ublas использует сложное метапрограммирование шаблонов, это будет крайне уродливо, и я бы не рекомендовал его.Вместо этого я написал бы функцию-оболочку около prod для вызова конкретной перегрузки, которую вы хотите.Вот довольно обобщенная обертка, которая должна работать с любой матрицей Ublas:

template <class E1, class E2> 
typename boost::numeric::ublas::matrix_matrix_binary_traits<
        typename E1::value_type, E1, 
        typename E2::value_type, E2>::result_type
my_prod(const boost::numeric::ublas::matrix_expression<E1>& e1, 
        const boost::numeric::ublas::matrix_expression<E1>& e2)
{
    return prod(e1, e2);
}

Затем вы можете вызвать my_pow, используя my_prod, например:для интереса, вот объявление указателя функции, которое вам нужно будет передать для разрешения параметров и перегрузок шаблона.Это объявляет указатель функции с именем prod_ptr, который указывает на конкретную перегрузку prod, которую вы хотите:

matrix_matrix_binary_traits<matrix<int>::value_type, matrix<int>, matrix<int>::value_type, matrix<int> >::result_type 
    (*prod_ptr)(const matrix_expression<matrix<int> >&, const matrix_expression<matrix<int> >&) = 
    &prod<matrix_matrix_binary_traits<matrix<int>::value_type, matrix<int>, matrix<int>::value_type, matrix<int> >::result_type, matrix<int>, matrix<int> >;

Тогда вы сможете вызвать my_pow, используя указатель на функцию:

my_pow(m, 2, prod_ptr);
2 голосов
/ 02 февраля 2012

Причина, по которой вы получаете ошибку компилятора, состоит в том, что существует много перегрузок функции prod, и при вызове my_pow компилятор должен знать, какую из них предоставить.Компилятор не может сделать вывод, что вы будете применять функцию pow к первому аргументу вашей функции, так что здесь он в недоумении.

Одним из решений было бы явное приведение указателя функции к нужному типу, нодля перегрузок uBlas prod определение правильного типа для приведения может быть довольно сложным.

Другим решением является создание объекта полиморфной функции, который делегирует соответствующую функцию pow.Обратите внимание, что реализация ниже делает огромное предположение, что prod( m, m) возвращает значение того же типа, что и m (или что-то конвертируемое в него), но опять же, это то же самое предположение, что делает ваш my_pow и временные значения,Трудно избежать созданий, если мощность e может быть определена только во время выполнения.

Пример класса полиморфной функции, который бы сработал:

struct my_prod
{
    template< typename M>
    M operator()( const M &left, const M &right) const
    {
        return prod( left, right);
    }

};

Теперь,если вы измените свой вызов на my_pow на это:

std::cout << my_pow(m, 2, my_prod()) << std::endl;

Это должно работать (это для меня).

...