Specialization of Member function of a Template Class

I have following template class defined -
<code>
template<class T, T invalidVal, int e>
Class Cls_Tmp
{
public: //Constructors and bunch of funcs
protected:
static inline bool dummy(T value) {
return 0;
}
T myval;
}
// I create a typedef
typedef Cls_Tmp<HANDLE, (HANDLE)NULL, 0> Cls_Tmp_New;
// For this Cls_Tmp_New class, I want to have my specialized dummy func
// So I do as below -
inline bool Cls_Tmp_New::dummy(HANDLE value)
{
//func body
}
</code>

The above code works without issue on Windows environment.

I wish to run it with minimum changes on a Linux environment.
I have g++-4.7
I typedef void * HANDLE somewhere in header files.

However, I get below error at the line where specialization of func is being done -
error: specializing member ‘Cls_Tmp<void*, 0u, 0>::dummy’ requires ‘template<>’ syntax

So I go ahead and add "template<>" on the same line just before "inline bool ..."
The error goes away.

1)I do not understand why this would happen. Have I really specialized the member function of the template class or not?

2)Here is my real question. When I try to use invalidVal (one of the parameters in the template class initialization) in specialization of dummy function - it fails with below compile error -
error: 'invalidVal' is not a member of 'Cls_Tmp_New {aka Cls_Tmp<void *, 0u, 0>}'
Any idea why this might be happening?
I am thoroughly confused by this behavior
What have I missed out?

Thanks!
Last edited on
This is one way of doing it.

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
#include <iostream>

template < typename T, T INVALID_VAL, int N > struct common_stuff
{
    static inline void foo() {}
    // whatever
};

template < typename T, T INVALID_VAL, int N > struct A : common_stuff<T,INVALID_VAL,N>
{
    using common_stuff<T,INVALID_VAL,N>::foo ;
    static inline bool dummy( T value )
    { std::cout << "generalization\n" ; foo() ; return value == INVALID_VAL ; }
};

template < void* INVALID_VAL, int N >
struct A<void*,INVALID_VAL,N> : common_stuff<void*,INVALID_VAL,N>
{
    using common_stuff<void*,INVALID_VAL,N>::foo ;
    static inline bool dummy( void* value )
    { std::cout << "specialization for void*\n" ; foo() ; return value != INVALID_VAL ; }
};

int main()
{
    A< int, -1, 100 >::dummy(50) ; // generalization
    A< void*, nullptr, 50 >::dummy(std::cout) ; // specialization for void*
}

@JLBorges, Thanks!
That looks like a neat way to do specialization.

I have one question, however. I am very new to templates, so please excuse my understanding.
Your method does specialization at the 'template class' level based on the signature of the parameters. Isn't it more of a overloading than specialization? Please correct me if I am wrong.

What I thought was when I typedef an 'instantiation' of a template class, that class is an actual full-fledged class.

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
// I have a template class
template<class T, T invalidVal, int e> class A
{ 
   static inline bool dummy(T value) 
  {
     return 0;
  }
}

// Now I create classes from the above template class with T=void*, invalidVal=NULL & e=0 
// And with T=void *, invalidVal=NULL & e=1 
// And I typedef these classes to use them later
typedef A<void *, (void *)NULL, 0> A_0;
typedef A<void *, (void *)NULL, 1> A_1;

// So now, what I was expecting was that A_0 & A_1 are classes and they can have their own 
// specialized dummy() method
// So I tried following - 
inline bool A_0::dummy(void *value) 
{
   return value != invalidVal;
}

inline bool A_1::dummy(void *value)
{
   return value == invalidVal;
}


But this specialization does not work as expected - using g++-4.7 - on Linux.
The above code works as is in a Windows environment.

For linux, as I had mentioned in my first post, I get following 2 errors -
1)specializing member ‘A<void*, 0u, 0>::dummy’ requires ‘template<>’ syntax &
2) invalidVal was not declared in this scope

Sorry for repeating the question.
But I am wondering if such specialization can be done or not and if so, then what am I missing that g++ is expecting?

Thanks!
Last edited on
A typedef is pretty much a #define just for types, with a few extra safety measures. So, imagine that instead of the typedefs you did this:
1
2
#define A_0 A<void *, (void *)NULL, 0>
typedef A_1 A<void *, (void *)NULL, 1>

This is pretty much what the compiler makes out of your code. So it thinks that you are making a specialisation like any other, so what it generates is actualy
1
2
3
4
5
6
7
8
9
inline bool A<void *, (void *)NULL, 0>::dummy(void *value) 
{
   return value != invalidVal;
}

inline bool A<void *, (void *)NULL, 0>::dummy(void *value)
{
   return value == invalidVal;
}

And everyone knows that for that kind of specialization you need the explicit specialization syntax (template<>
Last edited on
> Your method does specialization at the 'template class' level based on the signature of the parameters.

Yes.

> Isn't it more of a overloading than specialization?

It is partial specialization of a template class.


> when I typedef an 'instantiation' of a template class, that class is an actual full-fledged class.

A typedef does not create a new type - it just defines an alias for some type. A typedef of an 'instantiation' of a template class creates an alias for that particular instantiation.

What you really wanted to do is this:
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
#include <iostream>

template< typename T, T DEFV, int N > struct A
{
   static inline bool dummy(T value) ;
};

template< typename T, T DEFV, int N >
bool A<T,DEFV,N>::dummy( T value ) { std::cout << "generalization\n" ; return false ; }

template<>
bool A< void*, (void*)nullptr, 0 >::dummy( void* value )
{ std::cout << "specialization 0\n" ; return value == nullptr ; }

template<>
bool A< void*, (void*)nullptr, 1 >::dummy( void* value )
{ std::cout << "specialization 1\n" ; return value != nullptr ; }

typedef A< void*, (void*)nullptr, 0 > A_0 ;
typedef A< void*, (void*)nullptr, 1 > A_1 ;
typedef A< int, 3, 4 > B ;

int main ()
{
    A_0::dummy(nullptr) ; // specialization 0
    A_1::dummy(nullptr) ; // specialization 1
    B::dummy(9) ; // generalization
}
Last edited on
Topic archived. No new replies allowed.