5

I have a templated class Matrix. I want to specialize a function for the type complex, where T can be anything. I have tried this :

  6 template <typename T>
  7 class Matrix {
  8       public :
  9             static void f();
 10 };          
 11 template<typename T> void Matrix<T>::f() { cout << "generic" << endl; }
 12 template<> void Matrix<double>::f() { cout << "double" << endl; }
 13 template<typename T> void Matrix<std::complex<T> >::f() { cout << "complex" << endl; }

Line 13 does not compile. How can I do that ?

Maxime
  • 81
  • 3

3 Answers3

3

In lines 11 and 12 you have declaration of explicit specialization for a member of a class template which is allowed by C++ Standard 14.7/3 (14.5.2/2 contains a good example too). In line 13 you are trying to partially specialize a class template and that is not allowed in this form (this is partial specialization because you don't know the whole type std::complex<T> because it is still depends on T). You should partially specialize the whole class.

Kirill V. Lyadvinsky
  • 97,037
  • 24
  • 136
  • 212
  • as Assaf Lavie suggested, can't this be done using template template parameters without having to partially specialize the whole class ? A bunch of functions will be the same weither it's double or complex or float. I don't want to have to duplicate all of these functions. – Maxime May 12 '10 at 19:35
  • Probably a good idea will be to move all generic functions to the base class and partially specialize only inherited class. – Kirill V. Lyadvinsky May 12 '10 at 19:48
1

In fact, I found a clever way to do it through Boost. Since I don't want my library to be dependant on Boost, here is the code :

template <class T, T val> struct integral_constant
{
      typedef integral_constant<T, val> type;
      typedef T value_type;
      static const T value = val;
};    
typedef integral_constant<bool, true>  true_type;
typedef integral_constant<bool, false> false_type;
template <typename T> struct is_complex : false_type{};
template <typename T> struct is_complex<std::complex<T> > : true_type{};

template <typename T>
class Matrix {
      public :
            static void f() { f_( typename is_complex<T>::type() ); }
      private :
            static void f_( true_type ) { cout << "generic complex" << endl; }
            static void f_( false_type ) { cout << "generic real" << endl; }
};          
template<> void Matrix<double>::f() { cout << "double" << endl; }

This way, I can use function overloading and template to achievement my goal.

Maxime
  • 81
  • 3
0

As describe in the linked answer, what you'll need to do is specialize the entire class, rather than the simple function:

#include <iostream>
#include <complex>
using namespace std;

template <typename T>
class Matrix {
public :
    static void f();
};

template<typename T> void Matrix<T>::f() { cout << "generic" << endl; }
template<> void Matrix<double>::f() { cout << "double" << endl; }

template <typename T>
class Matrix<std::complex<T> > {
public:
    static void f() { cout << "complex" << endl; }
};

int main(void) {
  Matrix<complex<double> >::f();
  return 0;
}
Phil Miller
  • 36,389
  • 13
  • 67
  • 90
  • I don't understand. Why can I easily specialize it for double, but not for complex ? What I want is exactly avoid to specialize the entire class as that would means I need to duplicate code that should be reused. – Maxime May 12 '10 at 19:28
  • You can also extract f into another class and specialize that all you want: Matrix could implement `f()` as `SpecializedF::f(...)` – UncleBens May 12 '10 at 21:16