tags:

views:

74

answers:

3

Hi, i have below code

template <class T>
class Test
{
public:
    template<class U> void f(); //generic function

    template<> void f<char>(); //Specialization for char.
};

template <class T>
template<class U> 
void Test<T>::f()   //Definition of generic function
{
}

template<>
template<> void Test<char>::f<char>(){}  //Definition of specialization.

int main()
{
    Test<char> ob1;
    ob1.f<char>(); //Works fine.

    Test<int> ob2;
    ob2.f<char>();  //Produces linker error.
}

Linker error is

error LNK2019: unresolved external symbol "public: void __thiscall
Test<int>::f<char>(void)"

My requirement is: I should be able to pass any type to Test class and any type to function f(). I should be able to use all combinations of types like below.

  Test   f()
  --------------
  int    char
  char   int
  int    int

I can solve the error by defining another function like below.

template<>
template<> void Test<int>::f<char>(){}

But then what is the use of making Test class as Template ? How to make it work for all combinations ?

+3  A: 

My requirement is: I should be able to pass any type to Test class and any type to function f(). I should be able to use all combinations of types like below.

Why do you need an explicit specialization? Why do you unnecessarily want to make your code complex?

The following works for all combinations that you have listed.

template <class T>
class Test
{
public:
    template<class U> void f(); 
};

template <class T>
template<class U>
void Test<T>::f(){}   

int main()
{
    Test<char> ob1;
    ob1.f<char>(); //Works fine. T = char, U = char

    Test<int> ob2;
    ob2.f<char>();  //Works fine T = int, U = char
}
Prasoon Saurav
@Saurav: Incase if I want to have different implementation in f<char>(), i need to do specialization. Am doing this purely for learning purpose though.
bjskishore123
+5  A: 

C++03, §14.7.3/2:

An explicit specialization shall be declared in the namespace of which the template is a member, or, for member templates, in the namespace of which the enclosing class or enclosing class template is a member. An explicit specialization of a member function, member class or static data member of a class template shall be declared in the namespace of which the class template is a member.

Therefore you should declare your specialization outside of a class, for example:

template <class T>
class Test
{
public:
    template<class U> void f(); //generic function
};

template <class T>
template <class U> 
void Test<T>::f() {}  //Definition of generic function

template<>
template<>
void Test<char>::f<char>(){}  //Specialization.

int main()
{
    Test<char> ob1;
    ob1.f<char>();

    Test<int> ob2;
    ob2.f<char>();
}
vitaut
There is no need to specialize `Test<>` for `char` if you only need to specialize `Test<char>::f<char>`: you can remove the `Test<char>` specialization and just provide: `template <> template <> void Test<char>::f<char>() {}` to specialize only that function in that particular template instantiation.
David Rodríguez - dribeas
@"David Rodríguez - dribeas": Right, specialization Test<char> is not needed. Thanks for pointing this out.
vitaut
+3  A: 

The problem that you are facing is that you have declared the specialization of f for char in the Test template, and that is incorrect. The compiler is not detecting the error, but it is getting confused and interpreting that you want to provide the specialization of f for char in all template instantiations:

template <typename T>
struct Test {
   template <typename U> void f();
   template <> void f<char>();       // <- Incorrect
};

When you write Test<int> the compiler instantiates the template and is (mistakenly) accepting it and interepreting that there is an specialization of f for char in Test<int>.

Just remove the line, and you will get the code to compile. It will use the specialization only for Test<char>::f<char>(), and I am not sure whether that is what you want.

If your intention is specializing f for char with all instantiating types, that is not allowed. When you define a template specialization, all enclosing templates be specialized. A common work around is not providing an specialization but a different overload of the member function:

template <typename T>
struct Test {
   template <typename U> void f( U );
   void f( char );
};

But that won't help you much there, as you cannot provide different overloads for the same arguments (in your case no arguments). Also, in your case you must explicitly call the template to differentiate, and code that explicitly requests the template would not pick up the overload:

int main() {
   Test<int> t;
   t.f<char>(); // will call template, not "void f(char)"!!
}

Without more details on what you really want to achieve I cannot think on other potential solution to the issue.

David Rodríguez - dribeas