Not logged in, Join Here! or Log In Below:  
 
News Articles Search    
 

 Home / General Programming / Adding members in a template specialization? Account Manager
 
Archive Notice: This thread is old and no longer active. It is here for reference purposes. This thread was created on an older version of the flipcode forums, before the site closed in 2005. Please keep that in mind as you view this thread, as many of the topics and opinions may be outdated.
 
Reedbeta

February 22, 2005, 01:56 PM

I would like to be able to have a class template, and then for certain specializations of it, ADD new member functions only to the specialization, while keeping (inheriting) all the member functions from the unspecialized version. For example: in a matrix class templated by the number of rows and columns, it only makes sense to have an inverse operation when the matrix is square.

I thought of doing something like this:

  1. // MxN matrix
  2. template <int m, int n>
  3. class Matrix
  4. {
  5.      // Blah blah
  6. };
  7.  
  8. // Square matrix
  9. template <int n>
  10. class SquareMatrix: public Matrix<n, n>
  11. {
  12.      // Additional functions like inverse, for square matrices only
  13. };


However this creates two different classes rather than an actual specialization - icky.

I'm pretty sure this won't work:
  1. // Square matrix
  2. template <int n>
  3. class Matrix<n, n>: public Matrix<n, n>
  4. {
  5.      // Additional functions
  6. };


The class template appears to derive from itself, where what is intended is that the specialization derives from the unspecialized version of the class template.

Is there any clever way to do this, or am I asking for too much? =D

 
Sp0rtyt

February 22, 2005, 02:34 PM

I think in the days of the internet and bookstores with 30 day return policies, questions like these are really unacceptable. RTFB and if all else fails, RTFC.

 
Reedbeta

February 22, 2005, 02:53 PM

Thank you, sp0rtyt, for your utterly unhelpful response. For your information, I have already googled and couldn't find anything that dealt with this specific question. Sure, perhaps I could find the answer by poring over the standard (of which I don't currently have a copy handy), but if someone on this board knows the answer it takes two minutes of their time to post, as opposed to much more of my time to find the answer by research, or by trying random ideas in a compiler. That's the whole point of a forum like this, so people can be more efficient by sharing knowledge instead of having to research everything themselves. I would agree with you if this were a simple question, but this is a rather obscure one, so don't you think "unacceptable" is a bit harsh?

 
Nick

February 22, 2005, 03:24 PM

I think it's possible to work like this (off the top of my head):

  1.  
  2. template<int n, int m>
  3. class MatrixGenerator<n, m>
  4. {
  5.     class MatrixBase
  6.     {
  7.         float element[n][m];
  8.     };
  9.  
  10.     class SquareMatrixFunctions
  11.     {
  12.         Matrix<n, m> inverse();
  13.     };
  14.  
  15.     typedef typename META_CONDITIONAL_INHERIT(n == m, MatrixBase, SquareMatrixFunctions) Result;
  16. };
  17.  
  18. template<int n, int m>
  19. class Matrix : MatrixGenerator<m, n>::Result
  20.  

Where META_CONDITIONAL_INHERIT goes like this (credits go to Vesa Karvonen if I recall correctly):
  1.  
  2. #ifndef MetaMacro_hpp
  3. #define MetaMacro_hpp
  4.  
  5. //  Disables the "identifier was truncated to '255' characters in the browser information" warning
  6. #pragma warning (disable:4786)
  7.  
  8. namespace Meta
  9. {
  10. #define META_ASSERT(condition) typedef bool MetaAssert[2 * !!(condition) - 1]
  11.  
  12.         template<class T>
  13.         struct IsVoid
  14.         {
  15.                 enum {res = false};
  16.         };
  17.  
  18.         template<>
  19.         struct IsVoid<void>
  20.         {
  21.                 enum {res = true};
  22.         };
  23.  
  24. #define META_IS_VOID(T) Meta::IsVoid<T>::res
  25.  
  26.         template<bool>
  27.         struct Select
  28.         {
  29.                 template<class T0, class T1>
  30.                 struct Type
  31.                 {
  32.                         typedef T1 Res;
  33.                 };
  34.         };
  35.  
  36.         template<>
  37.         struct Select<true>
  38.         {
  39.                 template<class T0, class T1>
  40.                 struct Type
  41.                 {
  42.                         typedef T0 Res;
  43.                 };
  44.         };
  45.  
  46. #define META_SELECT(i, T0, T1) Meta::Select<i>::template Type<T0, T1>::Res
  47.  
  48.         template<class B0, class B1>
  49.         struct Inherit : B0, B1
  50.         {
  51.         };
  52.  
  53. #define META_INHERIT(B0, B1) Meta::Inherit<B0, B1>
  54.  
  55.         template<class B0, class B1>
  56.         class Catenate
  57.         {
  58.                 typedef typename META_SELECT(META_IS_VOID(B0), B1, B0) T0;
  59.                 typedef typename META_SELECT(META_IS_VOID(B0), void, B1) T1;
  60.  
  61.         public:
  62.                 typedef typename META_INHERIT(T0, T1) T01;
  63.                 typedef typename META_SELECT(META_IS_VOID(T1), T0, T01) Res;
  64.  
  65.         private:
  66.                 typedef typename META_SELECT(META_IS_VOID(T1), int, T1) CheckedT1;
  67.  
  68.                 META_ASSERT(META_IS_VOID(T1) || sizeof(Res) == sizeof(T0) + sizeof(CheckedT1));
  69.         };
  70.  
  71. #define META_CATENATE(B0, B1) Meta::Catenate<B0, B1>::Res
  72.  
  73.         template<bool condition, class B0, class B1>
  74.         class ConditionalInherit
  75.         {
  76.                 typedef typename META_CATENATE(B0, B1) MetaInherit;
  77.  
  78.         public:
  79.                 typedef typename META_SELECT(condition, MetaInherit, B0) Res;
  80.         };
  81.  
  82. #define META_CONDITIONAL_INHERIT(condition, B0, B1) Meta::ConditionalInherit<condition, B0, B1>::Res
  83. }
  84.  
  85. #endif   // MetaMacro_hpp
  86.  

 
I'M BRIAN FELLOWS

February 22, 2005, 05:41 PM

THAT'S THE DEVIL'S THINKING.

 
Altair

February 22, 2005, 07:39 PM

Probably the cleanest way to do that would be to implement the inverse as non-member function like:

  1.  
  2. template<unsigned size_> void invert(Matrix<size_, size_> &result_, const Matrix<size_, size_> &input_);

Cheers, Altair

 
Jeroen

February 23, 2005, 02:54 AM

You could use policy classes to do this. Basically, whether a matrix is square or not becomes a template parameter. If the matrix is square, the template class derives from a policy class that provides your additional functionality. If it is not square, it derives from a policy class that does not provide this functionality.

Read up on policy based class design here:

http://www.informit.com/articles/article.asp?p=167842&seqNum=1

 
Victor Widell

February 23, 2005, 03:58 AM

Why not just provide the inverse() method for all matrices? Just make it fail on n!=m, since it must be able to fail anyway (for irrevesible matrices).

 
This thread contains 8 messages.
 
 
Hosting by Solid Eight Studios, maker of PhotoTangler Collage Maker.