16

This little piece of code triggers the linker's anger when included on at least two translation units (cpp files) :

# ifndef MAXIMUM_HPP
# define MAXIMUM_HPP

template<typename T>
T maximum(const T & a, const T & b)
{
    return a > b ? a : b ;
}

/* dumb specialization */
template<>
int maximum(const int & a, const int & b)
{
    return a > b ? a : b ;
}

# endif // MAXIMUM_HPP

But compiles and links fine with one translation unit. If I remove the specialization, it works fine in all situations. Here is the linker message :

g++ -o test.exe Sources\test.o Sources\other_test.o
Sources\other_test.o:other_test.cpp:(.text+0x0): multiple definition of `int maximum<int>(int const&, int const&)'
Sources\test.o:test.cpp:(.text+0x14): first defined here

Aren't templates allowed to be instantiated multiple times ? How to explain this error and how to fix it ?

Thanks for any advice !

overcoder
  • 1,523
  • 14
  • 24
  • You probably should return a reference from your functions. – Daniel Oct 25 '11 at 01:05
  • It was just an example resulting from tracking down the errors I encountered in a more complex code. I think the example can be more clear without any references at all :) – overcoder Oct 25 '11 at 01:11

2 Answers2

31

Its because complete explicit template specializations must be defined only once - While the linker allows implicit specializations to be defined more than once, it will not allow explicit specializations, it just treats them as a normal function.
To fix this error, put all specializations in source file like:

// header

// must be in header file because the compiler needs to specialize it in
// different translation units
template<typename T>
T maximum(const T & a, const T & b)
{
    return a > b ? a : b ;
}

// must be in header file to make sure the compiler doesn't make an implicit 
// specialization
template<> int maximum(const int & a, const int & b);

// source

// must be in source file so the linker won't see it twice
template<>
int maximum(const int & a, const int & b)
{
    return a > b ? a : b ;
}
Daniel
  • 30,896
  • 18
  • 85
  • 139
14

Declare the functions inline

// must be in header file because the compiler needs to specialize it in
// different translation units
template<typename T>
inline T maximum(const T & a, const T & b)
{
    return a > b ? a : b ;
}

/* dumb specialization */
template<>
inline int maximum(const int & a, const int & b)
{
    return a > b ? a : b ;
}
Ayjay
  • 3,413
  • 15
  • 20
  • 1
    Many thanks ! I think we can obtain a complete and precise answer if we could merge yours with Dani's answer. – overcoder Oct 25 '11 at 01:14