Template Specialization Question

Mar 14, 2011 at 6:00am
I have a function declared as such in a header file:

1
2
3
4
5
6
template <class T>
std::string to_string(T thing) {
	std::stringstream ret;
	ret<<thing;
	return ret.str();
}


This compiles fine, however, when I try to add a specialization below it:

1
2
3
4
template <> //just for practice really
std::string to_string(std::string thing) {
	return thing;
}


I receive a bunch of linker errors stating that the specialized version of the function is already defined in the other object files. What exactly is the problem? Do I need to put the specialization somewhere else?
Mar 14, 2011 at 7:23am
You cannot make a specialization of a template function.

EDIT: Apparently I was wrong. The code you posted compiles and links fine on mingw.

EDIT 2: One thing that comes to my mind is that this specialization is not "visible" everywhere where the base template is. In this situation one compilation unit could use std::string to_string(std::string thing) generated based on the base template, and another compilation unit could use std::string to_string(std::string thing) generated from the specialization, what would lead to link errors.

EDIT 3: Tested again with two compilation units, and mingw generates errors even if visibility of the base tamplate and its specialization is the same. It looks that the compiler treats the specialization just like a regular function, i.e. its symbol name is global. Adding static to the function's declaration helped.
Last edited on Mar 14, 2011 at 7:56am
Mar 14, 2011 at 7:43am
Are you using Microsoft Visual Studio??
Mar 14, 2011 at 9:35am
There are no specializations of function templates. But you can have several function templates with the same function name. The only difference between instantiated templates and normal overloads is that 1) templates have lower priority when it comes to overload resolution and do not contend with non-template functions (therefore not causing ambiguity errors with them) 2) template functions are instantiated on a per-need basis.

So, I would understand ambiguity error from the compiler, but linker error? May be the problem is that you instantiate in one translation unit the parametrized template with string and in another the non-parametrized template and the mangled names of the resulting compiled functions are the same and the linker dies. That would explain why adding static modifier fixes the problem. But I still can not understand why you don't get ambiguity error for overload resolution during compilation. May be I don't understand overload resolution that well.

Regards
Last edited on Mar 14, 2011 at 9:36am
Mar 14, 2011 at 9:47am
samples:
mytemplate.h
1
2
3
4
5
#ifndef MYTEMPLATE_H
#define MYTEMPLATE_H
template <class T> T max(T t1, T t2);
#include "myTemplate.cpp"
#endif // MYTEMPLATE_H 

myTemplate.cpp
1
2
3
4
5
6
7
8
9
10
11
12
#include "myTemplate.h"
#include <iostream>
#define V std::string
template <class T> T max(T t1, T t2)
{
    return (t1 > t2) ? t1 : t2;
}

template <> V max<V>(V t1, V t2)
{
    return (t1 > t2) ? t1 : t2;
}


tmain.cpp
1
2
3
4
5
6
7
8
9
10
#include "myTemplate.h"
#include <iostream>

int main(void)
{

    std::cout << max<std::string>(std::string("right"), std::string("wrong")) << std::endl;
    std::cin.get();
    return 0;
}
Mar 14, 2011 at 10:27am
True, this works. I was confused because partial template specialization is not available. But I didn't know that full template specialization works ok with functions. I need to look into that stuff more seriously :)
Mar 14, 2011 at 12:51pm
Anyway the linker error is because the "specialized" version needs to be (declared) inline.
Mar 14, 2011 at 1:14pm
All template specializations need to be inline? You mean, like, always?

And is there a difference between
template <> std::string to_string(std::string thing) and
template <> std::string to_string<std::string>(std::string thing)?

Are they both template specializations of the to_string template, or only the latter one and the former one is separate template?
Mar 14, 2011 at 2:17pm
Hi simeonz,
The latter one is good declaration for specializations template.
Mar 14, 2011 at 3:21pm
Yes, that was my guess also - the second one is specialization like in your example. But the one from the snippet in the original post is not specialization, but separate template, or am I wrong?
Mar 14, 2011 at 4:45pm
Putting the implementation of a concrete (non-template) function in a header file is the same thing as putting a global variable in a header file, only the duplicate symbol definition linker error complains about the name of the function instead of the name of the variable.
Mar 14, 2011 at 5:00pm
jsmith wrote:
Putting the implementation of a concrete (non-template) function in a header file is the same thing as putting a global variable in a header file, only the duplicate symbol definition linker error complains about the name of the function instead of the name of the variable.



To confirm what JSmith said - the following is from the book C++ Templates - The Complete Guide concerning function templates.

A full specialization is in many ways similar to a normal declaration (or rather, a normal redeclaration). In particular, it does not declare a template, and therefore only one definition of a noninline full function template specialization should appear in a program.
Mar 14, 2011 at 5:18pm
Thanks! Following up with the "specializations are basically normal functions" info, I did this:

Header:
1
2
3
4
5
6
7
8
9
template <class T>
std::string to_string(T thing) {
	std::stringstream ret;
	ret<<thing;
	return ret.str();
}

template <>
std::string to_string(std::string thing);


And moved the definition to the .cpp and it compiled fine.
Mar 14, 2011 at 6:26pm
That's very useful info. But does this mean that full template specialization participates in overload resolution with the same priority as non-template function overloads?

And I still don't understand what is the difference between the syntaxes
template <> std::string to_string(std::string thing) and
template <> std::string to_string<std::string>(std::string thing)?
Are they the same thing? You certainly can not use the former syntax in circumstances like these:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>

template <int N> int f()
{
  return N;
}

template <> int f<5>()
{
  return 6;
}

int main(void)
{

    std::cout << f<5>() << std::endl;
}
Mar 14, 2011 at 6:35pm
They are the almost the same. The first allows the compiler to infer the template type from the arguments (as normal) and the second type lets you tell the compiler explicitly. In your example, the compiler can't guess the template arguments from the function, so you need to specify.

EDIT: Misinterpreted something.
Last edited on Mar 14, 2011 at 6:37pm
Mar 14, 2011 at 6:57pm
Oh, ok. So it is the same mechanism as in template instantiation. You either specify the template arguments explicitly or rely on their deduction. Boy, was I confused on the subject.

To answer my last question. Fully specialized function templates are apparently assigned lower priority to non-template functions in overload resolution:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <typeinfo>

template <typename T> void f(T)
{
  std::cout << "template: " << typeid(T).name() << std::endl;
}

template <> void f(int)
{
  std::cout << "spec. template: int" << std::endl;
}

void f(int)
{
  std::cout << "non-template: int" << std::endl;
}

int main(void)
{
  f(int()); //prints "non-template: int"
}
Mar 14, 2011 at 7:17pm
@simeonz:

Here's a link that might help you out with your question: http://www.gotw.ca/publications/mill17.htm
Be careful about what compiler you are using for your test. For me, different versions of gcc give
different results for the code examples given in the link.
Mar 14, 2011 at 7:42pm
Overload resolution of base templates. This is first time I encounter that. Thanks a lot.
Topic archived. No new replies allowed.