3

行列指数を実行しようとしていますが、べき乗関数をコピーして貼り付けたくなく、クラステンプレートを使用したいと思います。問題は、ブースト行列の場合、行列を乗算するには、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を計算する

4

2 に答える 2

2

コンパイラ エラーが発生する理由は、prod関数のオーバーロードが多数あり、コンパイラの呼び出し時にmy_powどれを提供するかを知る必要があるためです。コンパイラは、関数の最初の引数に pow 関数を適用することを推測できないため、ここで途方に暮れています。

1 つの解決策は、関数ポインターを適切な型に明示的にキャストすることですが、uBlasprodオーバーロードの場合、キャストする適切な型を決定することは非常に複雑になる可能性があります。

もう 1 つの解決策は、適切な 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;

それはうまくいくはずです(私にとってはそうです)。

于 2012-02-01T20:57:50.897 に答える
2

2 つの問題があります。まず、テンプレート化された関数であるため、関数ポインターとして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);
于 2012-02-01T20:59:06.643 に答える