Как передать функцию повышения матрицы Prod() в качестве функции умножения?
Я пытаюсь выполнить матричное возведение в степень, но я не хочу копировать / вставлять свою функцию возведения в степень, а скорее использовать шаблоны классов. Проблема в том, что для повышения матриц, чтобы умножить матрицы, вы используете 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 ответа
Причина, по которой вы получаете ошибку компилятора, состоит в том, что существует много перегрузок 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;
Это должно работать (это для меня).
Есть две проблемы. Первый, 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
вот так:
my_pow(m, 2, my_prod<matrix<int>, matrix<int> >)
Просто для забавы, вот объявление указателя функции, которое вам нужно будет передать для разрешения параметров и перегрузок шаблона. Это объявляет указатель на функцию с именем 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);