methods template specialization

I have a template class MyClass (with template argument typename), with a template method:

1
2
3
4
5
template <typename Derived>
class MyClass
{
  template <int N> inline void method();
};


N can be either 0 or 1. I'd like to specilize that method in this way:

1
2
3
4
5
6
7
8
9
10
11
12
13
template <typename Derived>
template<>
inline void MyClass<Derived>::method<0>()
{
  /* Some code here... */
}

template <typename Derived>
template<>
inline void MyClass<Derived>::method<1>()
{
  /* Some code here... */
}


But that doesn't compile: g++ returns
1
2
3
MyClass.h:104: error: invalid explicit specialization before ‘>’ token
MyClass.h:104: error: enclosing class templates are not explicitly specialized
MyClass.h:105: error: template-id ‘method<0>’ forvoid MyClass<Derived>::method()’ does not match any template declaration


Can I specialize with templates a method of a class? If yes, how?
Or is it impossible since partial specilized functions are not allowed ?
Last edited on
you're missing your argument list (parenthesis)

1
2
3
4
5
template <typename Derived>
template <>
inline void MyClass<Derived>::method<0>()  // <--- parenthesis
{
}


EDIT -- crap apparently this isn't the only problem. I just tried my fix and it isn't working either. Sorry about that.
Hold...

EDIT2 -- apparently you can't do a partial specialization like this. "enclosing class templates are not explicitly specialized
" seems to imply that the entire template (ie: the class) would need to be specialized as well. Which kind of makes sense when you think about it -- because if the class isn't specialized there's no guarantee that the funciton will be able to apply to the class. This seems like a strange use for a template anyway (why not just pass N as a parameter?)

<unrelated>
On a side note: this 'Derived' template class thing is throwing up a big red flag for me. Making a templated parent class that takes the child class as its template argument defeats the entire point of using inhertiance because the parent classes are no longer the same type. I don't know if this is what you're doing or not, but if it is you should really reconsider.
</unrelated>
Last edited on
@Disch:

This pattern is called the Curiously Recurring Template Pattern (CRTP) and is used quite commonly. For examples, see the boost::operator library, boost::spirit library, etc. Having said that, not all uses of CRTP
make sense, and it is impossible to know what OP is doing with the class.
The parenthesis are only a copy-paste error. I'll edit my previous post.

Ok, I'll explain wath is my goal: I'm constructing a QR decomposition for matrices. Each matrix has two compile-time variables (which are part of an enum) RowsAtCompileTime and ColsAtCompileTime. These variables can be either an int or the special value Dinamic. The scalar type is "saved" as typedef in the matrix class (MatrixType::Scalar is a typedef to a type, like e.g. float, double or complex<long double>). A class NumTraits stores some informations about the scalar in this way:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* This code is part of Eigen (eigen.tuxfamily.org) */

template<typename T_> struct NumTraits<T_>{ };

template<> struct NumTraits<double>
{
  typedef double Real;
  typedef double FloatingPoint;
  enum {
    IsComplex = 0,
    HasFloatingPoint = 1,
    ReadCost = 1,
    AddCost = 1,
    MulCost = 1
  };
};


In my QR class I store some informations at compile-time in this way:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template<class MatrixType>
class QR
{
public:
  typedef typename MatrixType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;

  enum {
    Rows = MatrixType::RowsAtCompileTime,
    Cols = MatrixType::ColsAtCompileTime,
    isDynamic = (MatrixType::RowsAtCompileTime == Dynamic) ? 1 : 0,
    isComplex = NumTraits<Scalar>::IsComplex,
    q_Cols = Cols < Rows ? Cols : Rows-1,
    m_Cols = Cols < Rows ? (Cols*Rows - Cols*(Cols+1)/2) : (Rows*(Rows-1)/2)
  };


This class has a (private) method compute_(), which actually does the decomposition, but this method has a different behaviour for dynamically-sized matrices. So, the constructor of QR must decide which method use, but since the decision must be taken at compile-time. My idea was:

1
2
3
4
5
QR::QR()
{
  /* some "normal" code */
  compute_<isDynamic>();
}


With two different specializations for compute_<0> and compute_<1>.

Is this possible?
Last edited on
You could try inheritance:

1
2
3
4
5
6
7
8
9
10
11
class QRBase {
  virtual void compute_() = 0;
};

class QRStatic : public QRBase {
  void compute_();
};

class QRDynamic : public QRBase {
  void compute_();
};

I think this is what you want:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <boost/type_traits.hpp>
#include <iostream>

using namespace std;

template< typename T >
class Foo {
    public:
        void Frobnicate() {
            cout << __PRETTY_FUNCTION__ << endl;
            frobby( boost::is_pod<T>::type() );
        }

        void frobby( boost::true_type ) {
            cout << "true_type called" << endl;
        }

        void frobby( boost::false_type ) {
            cout << "false_type called" << endl;
        }

    private:
        int t;
};

int main() {
    Foo<int> f;
    f.Frobnicate();
    Foo< Foo<int> > f2;
    f2.Frobnicate();
}

Topic archived. No new replies allowed.