Trying to do Explicit specialization of member function template

Hello everybody. Im fairly new to C++ and Ive been trying to teach it to myself as fast as possible, so I can later jump to program with DirectX in VC soon (I have some experience with C). Right now, I am studying templates and I have a problem with the following code:

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
29
30
31
32
33
// Test.h
#ifndef TEST_H
#define TEST_H
#include <iostream>

class Test 
{
  public:
    template <typename T>
    void function (T data) {
      std::cout << data << std::endl;
    }
};

// Specialization of template function
template <>
void Test::function (char data) {
  std::cout << 'Z' << std::endl;
}

#endif // TEST_H

// main.cpp
#include <iostream>
#include "include\Test.h"

int main ()
{
  Test t = Test();
  t.function(15);
  t.function('a');
  return 0;
}


I am trying to compile this with g++ in CodeBlocks 10.05, but the linker gives me an error in line 16 of Test.h, saying: multiple definition of void Test::function <char> (char) first defined here

Can somebody please tell me what am I doing wrong and how to properly explicitly specialize class member functions?
Also, I want to know if it is proper to define templates in the header files, or should I do it in the source files? I know that templates must be defined when there are declared but, is it possible to separate templates in a header and a source file?

Sorry for doing so many questions at once, but I want to be sure =D
I appreciate your responses.
Last edited on
The reason that templates have to be defined in headers is that the compiler wouldn't know for which template parameters to compile the code and which functions to instantiate. However in case of full template specialization, this question is no longer there - and the function is compiled as normal. So when you include your header in several files - the function is defined in multiple object files, which leads to the error you get.

So to fix this, you need to move the definition of your specialization into a cpp file, but you have to leave the declaration in the header file to instruct the compiler that there exists an explicit specialization of that function somewhere else, so that it doesn't instantiate the template function for char when it meets a need for it.
Thanks for answering and explaining so clearly, but even though I followed your advice, I still can't compile the code. Here is what I did:

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
// Test.h
#ifndef TEST_H
#define TEST_H
#include <iostream>

class Test
{
  public:
    template <typename T>
    void function (T data) {
      std::cout << data << std::endl;
    }

    template <> void function (char);
};

#endif // TEST_H

// Test.cpp
#include <iostream>
#include "Test.h"

template <>
void Test::function (char a) {
  std::cout << 'Z';
}

// main.cpp unchanged 


Now the linker sends an error on line 14 of Test.h saying: explicit specialization in non-namespace scope 'class Test'. Curiously, I placed the specialization after defining the class precisely because I read in another forum that that would solve this error. Guess I fall back to it again =/

I cite what I found:
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.


However, how can I place the specialization in the same namespace as the class that contains it (Test) since I didn't explicitly defined a namespace for that class? In another forum I read that I shall not specialize member functions, but rather specialize class templates, is this true? Because I can imagine that there will be occasions where I would want to specialize only 1 function rather than the entire class.
Last edited on
You need the <char> after your function IIRC:

1
2
template<>
void function<char> (char);


However, how can I place the specialization in the same namespace as the class that contains it (Test) since I didn't explicitly defined a namespace for that class?


You would put it in the global namespace.

In another forum I read that I shall not specialize member functions, but rather specialize class templates, is this true? Because I can imagine that there will be occasions where I would want to specialize only 1 function rather than the entire class.


I don't think this is the case but I haven't tested it.
i suggest you to read topic
Templates and multiple-file projects in the following link that may be most useful to you.
http://www.cplusplus.com/doc/tutorial/templates/
Last edited on
However, how can I place the specialization in the same namespace as the class that contains it (Test) since I didn't explicitly defined a namespace for that class?


Exactly how you did it in the first version of your code. Just remove the body of the function and replace it with a ";"

1
2
template <>
void Test::function (char a);


You need the <char> after your function IIRC

Yeah, I also felt it was missing, but in this case compilers (g++ in case of oldcrow and MSVC in my case) seem to correctly deduce the template argument.
Last edited on
Thanks everybody for your help! I could finally compile this simple code =)
I think I'm going to study this more thoroughly so I can clear all my doubts. I'm going to post the definite code just in case:

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
29
30
31
32
33
34
35
36
37
38
39
// Test.h
#ifndef TEST_H
#define TEST_H
#include <iostream>

class Test
{
  public:
    template <typename T>
    void function (T data) {
      std::cout << data;
    }
};

// Going to follow firedraco's and KRAkatau's advice here
template <>
void Test::function <char> (char data);

#endif // TEST_H

// Test.cpp
#include "Test.h"

template <>
void Test::function <char> (char data) {
  std::cout << 'Z',
}

// main.cpp
#include <iostream>
#include "include\Test.h"

int main ()
{
  Test t = Test();
  t.function(15);
  t.function('a');
  return 0;
}


Fixed!!
Last edited on
Topic archived. No new replies allowed.