PDA

View Full Version : template specialization and inline member functions


ashweta
01-09-2007, 12:01 AM
I have got a problem with specializing member functions of a class template. When the specialized function is called from another specialized function, the compiler throws error:

tmpl.h

#include <iostream.h>

template <int n>
class myClass
{
public:
void myFunc ();
void inFunc();
};

tmpl.cxx

#include "tmpl.h"

template<>
void myClass<2>::inFunc ()
{
myFunc();
}

template <>
void myClass<2>::myFunc () const
{
std::cout << "Two is very special!\n";
}

int main( int argc, char** argv )
{
myClass<2> c2;
c2.inFunc();
return 0;
}

template class myClass<1>;
template class myClass<2>;


g++ tmpl.cxx

tmpl.cxx:19: error: specialization of void myClass<n>::myFunc() [with int n = 2] after instantiation
tmpl.cxx:19: error: prototype for `void myClass<n>::myFunc() [with int n = 2]' does not match any in class `myClass<2>'
tmpl.h:6: error: candidate is: void myClass<n>::myFunc() [with int n = 2]
tmpl.cxx:19: error: `void myClass<n>::myFunc() [with int n = 2]' and `void myClass<n>::myFunc() [with int n = 2]' cannot be overloaded

I am not able to understand why this is happening. Anybody any insight?

Please note that the above code is a simplification of my actual code. So, don't suggest to specialize the whole class. The actual class contains other member functions which are not to be specialized.

SpreeTree
01-09-2007, 12:56 AM
Specialisation of a single member function is not possible in the C++ standard. It is just something they don't let you do.

The only option is to specialise the entire class with n being 2.

There are hacky ways to get around this apparently, though I have not actually used or investigated them, as they seem to be using holes in the standard, which generally means it won't work on different compilers.


Spree

Reedbeta
01-09-2007, 01:53 AM
BTW, ashweta, please use the [ code ] [ /code ] tags when posting code snippets or compiler output.

One way to work around this is to put common code in a base class. Then define your class to include only the member functions that need specialization, in each case inheriting the rest of the functionality from the base. Something like this:


template <int n>
class myClassBase {
// Functions common to all n go here
void myFunc ();
};

// General version of myFunc
template <int n>
void myClassBase<n>::myFunc () {
// ...
}

// Derived class, with specialized override of myFunc for n = 2
template <int n>
class myClass: public myClassBase<n> {}; // empty
template <>
class myClass<2>: public myClassBase<2> {
void myFunc ();
};

// in a .cpp file: specialized version of myFunc
template <>
void myClass<2>::myFunc () {
// ...
}

ashweta
01-09-2007, 02:19 AM
Thank you for your reply, Reedbeta.

Yes, it seems like a good idea to use a derived class for the specialized functions.

Other than that I discovered that g++ stops screaming for my specific problem, if either I
1. declare the specialized version of myFunc before inFunc.
2. or, move the specialized definition of myFunc before inFunc.

-Shweta

.oisyn
01-09-2007, 03:15 AM
Specialisation of a single member function is not possible in the C++ standard. It is just something they don't let you do.

The only option is to specialise the entire class with n being 2.
Nonsense, his code is perfectly fine, except for the order of declarations (which are implied by the definitions in his example), and the fact that he defines myfunc() as const while the declaration in the class was non-const. Perhaps you are mistaken with partial specializations, which are indeed not allowed on a per-member-function basis?

ashweta: I bet you couldn't just swap the order of the function definitions otherwise you would probably already have done that ;). If the issue is a recursive dependency, you could declare the specializations before defining them

#include "tmpl.h"

template<>
void myClass<2>::myFunc(); // forward declaration

template<>
void myClass<2>::inFunc ()
{
myFunc();
}

// this works fine now:
template <>
void myClass<2>::myFunc () const
{
std::cout << "Two is very special!\n";
}

If you want to let the user specialize his own functions, you should call another function which is name-dependent on the template parameters, like Reedbeta showed. If you want to specialize a function of another class you can't change, then you're basically just screwed - completely specializing the whole class is the only way, however you still need to specialize it before it's first use :)

SpreeTree
01-09-2007, 07:32 AM
Perhaps you are mistaken with partial specializations, which are indeed not allowed on a per-member-function basis?


That may well be the case, and if it is I do apologise :)

Though I was attempting to get something similar working on the PS3 only a few weeks ago, with out any success. I can't remeber the exact case, but it was impossible. Maybe thats where my confusion came from - who knows! :)

Spree