4
votes

I have the following class;

template<int N, int M, int K>
class BaumWelch
{
  //lots of stuff
  const TransitionMatrixTemplate<N, M> randomA()
  { //.... }
}

now I would like to specialize the method randomA for N=1. How can I do it?

I tried following this question: Template specialization of a single method from a templated class, but it doesn't seem to work with partial specialization. This question: C++ partial method specialization seems more relevant, but it suggest specializing the whole class (which is quite big in my case). Is it possible to specialize the whole class, but actually specialize only this one method?

3

3 Answers

2
votes

You can't partially specialize function templates, but you can pass the work off to class templates. Here's a fully working example:

#include<iostream>
using namespace std;

// This first template isn't important, it's just the return value from your function
template <int N, int M>
struct TransitionMatrixTemplate {
        void print_me() const {
                cout << N << ',' << M << endl;
        }
};

// We need to announce the existence of the BaumWelch class template early here,
// in order that it can appear in the signature of our impl_randomA class.
template<int N, int M, int K>
struct BaumWelch;

// Now, the first important bit of code.  The default implementation
template<int N, int M, int K>
struct impl_randomA {
        static TransitionMatrixTemplate<N,M> f(BaumWelch<N,M,K> * This) {
                return TransitionMatrixTemplate<N,M>();
        }
};

// Next, is the partially specialized version.
template<int M, int K>
struct impl_randomA<1,M,K> {
        static TransitionMatrixTemplate<1,M> f(BaumWelch<1,M,K> * This) {
                cout << "<Special for N=1> ";
                return TransitionMatrixTemplate<1,M>();
        }
};

// Finally, The BaumWelch class and its call out to impl_randomA.
template<int N, int M, int K>
struct BaumWelch {
        const TransitionMatrixTemplate<N, M> randomA() {
                return impl_randomA<N,M,K> :: f(this);
        }
};

int main() {
        BaumWelch<2,3,4>() . randomA() . print_me();
        BaumWelch<1,3,4>() . randomA() . print_me();
}
6
votes

I would like to specialize the method randomA for N=1. How can I do it?

You've discovered that partial specialization for functions is not allowed.

However, you can fully specialize a "detail" implementation of the code.

  template<int TheN>
  detail_randomA();

  const TransitionMatrixTemplate<N, M> randomA()
  {
      return detail_randomA<N>();
  }

And outside the class declaration:

  template<int N, int M, int K>
  template<int TheN>
  BaumWelch<N,M,K>::detail_randomA()
  {
      //lots of stuff when N != 1
  }

  template<int N, int M, int K>
  template<>
  BaumWelch<N,M,K>::detail_randomA<1>()
  {
      //lots of stuff when N == 1
  }
1
votes

The short answer is "you don't".

A way to make it easy to do what you want to do (have randomA act differently for N=1) would be to stuff const TransitionMatrixTemplate<N, M> randomA() into a CRTP parent, then partially specialize that for N=1.

template<typename D, int N, int M, int K>
struct Bob_Base {
  static_assert( std::is_base_of< D, Bob_Base<D, N, M, K> >::value, "D must be derived from Bob_Base" );
  D* self() { return static_cast<D*>(this);
  D const* self() const { return static_cast<D*>(this);
  const TransitionMatrixTemplate<N, M> randomA()
  {
    // use self()-> instead of this-> in here to access Bob methods and date
  }
};
template<typename D,int M, int K>
struct Bob_Base< D, 1, M, K > {
  static_assert( std::is_base_of< D, Bob_Base<D, N, M, K> >::value, "D must be derived from Bob_Base" );
  D* self() { return static_cast<D*>(this);
  D const* self() const { return static_cast<D*>(this);
  const TransitionMatrixTemplate<1, M> randomA()
  { /* N=1 version  */ }
};

template<int N, int M, int K>
struct Bob : Bob_Base<Bob<N, M, K>, N, M, K>
{
  //lots of stuff, but no TransitionMatrixTemplate
}

this is only important if the code where N==1 cannot compile (or vice versa).