Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++ partial specialization of template class member functions

There do appear to be a few closely related questions, but I'm struggling to work out how to apply their solutions.

I have a traits class, shown below, for manipulating matrices that I am using with boost::numeric:ublas::matrix (amongst other matrix implementations). I would like to partially specialize just the switch_storage_order as shown in the comment, however this fails as functions cannot be partially specialized.

I don't want to partially specialize the matrix_traits struct as this entails the overhead of re-defining all its members. One solution would be to separate each matrix-related function into its own struct, but it would be nice to keep them grouped in the one traits class.

Any ideas? Feel free to comment on the general application of the traits concept as well.

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

enum matrix_storage_order {row_major, column_major};

template<class matrix_type>
struct matrix_traits {
  // Default expects c-style row_major storage order.
  static matrix_storage_order get_storage_order(const matrix_type& m)
  { return row_major; }

  // By default can't change storage order so simply transpose.
  static void switch_storage_order(matrix_type& m) { m.transpose(); }
};

namespace ublas = boost::numeric::ublas;

/* This doesn't work with error C2244:
  * 'matrix_traits<matrix_type>::switch_storage_order' : unable to match function
  * definition to an existing declaration
  */
// template<class value_type>
// void matrix_traits<ublas::matrix<value_type> >::switch_storage_order(
//     ublas::matrix<value_type>& m) {
//   m = boost::numeric::ublas::trans(m);
// }

typedef boost::numeric::ublas::matrix<double> matrix_double;

template<>
void matrix_traits<matrix_double>::switch_storage_order(matrix_double& m) {
  m = boost::numeric::ublas::trans(m);
}

template <class matrix_type>
void function_requiring_column_major_storage_order(matrix_type& m) {
  bool switch_order =
    matrix_traits<matrix_type>::get_storage_order(m) == row_major;
  if (switch_order) matrix_traits<matrix_type>::switch_storage_order(m);
  // ... Do some work on m.
  if (switch_order) matrix_traits<matrix_type>::switch_storage_order(m);
}

int main() {
  matrix_double m;
  // ... Fill the matrix.
  function_requiring_column_major_storage_order(m);
}
like image 659
Rai Avatar asked Oct 21 '22 07:10

Rai


2 Answers

if you can change the implementation of static void switch_storage_order(matrix_type& m), you may use something like:

// By default can't change storage order so simply transpose.
static void switch_storage_order(matrix_type& m) { transposer<matrix_type>()(m); }

with

// generic case
template <typename T>
struct transposer {
    void opearator () (T& m) const { m.transpose(); }
};

// your specialization.
template<typename T>
struct transposer<ublas::matrix<T>> {
    void opearator () (ublas::matrix<T>& m) const { m = boost::numeric::ublas::trans(m); }
};
like image 72
Jarod42 Avatar answered Nov 12 '22 20:11

Jarod42


When ever I would like to (but can't) partially specialize a template function what I end up doing is to simply NOT specialize the template function at all but simply make it forward its actual work to a static function of an internal helper template class / struct. Then I go ahead and partially specialize that template class / struct.

To give you an example (say I want to partially specialize doStuff() for cases where B is bool):

namespace detail
{
    // primary template ... implement general case here
    template < typename A, typename B >
    struct DoStuffImpl
    {
        inline static void impl( A a, B b )
        {
            // ...
        }
    };

    // partial specialization for < A, bool >
    template < typename A >
    struct DoStuffImpl< A, bool >
    {
        inline static void impl( A a, bool b )
        {
            // ...
        }
    };
}

template < typename A, typename B >
void doStuff( A a, B b )
{
    detail::DoStuffImpl< A, B>::impl( a, b );
}
like image 21
antred Avatar answered Nov 12 '22 20:11

antred