1

pid.h

#include <iostream>

template <class T>
void f(T t);

pid.c

#include "pid.h"

template <class T>
void f(T t) {
  std::cout << t;
}

template
void f<int>(int);

pid2.c

#include "pid.h"

template <class T>
void f(T t) {
  std::cout << 55;
}

template
void f<int>(int);

main.c

#include "pid.h"

int main()
{
  f(1);
  return 0;
}

command:

g++ "-IC:\\Users\\kam\\workspace\\boost_1_56_0" -O0 -g3 -pg -Wall -c -fmessage-length=0 -std=c++11 -pthread -o "src\\pid2.o" "..\\src\\pid2.cpp" 
g++ "-IC:\\Users\\kam\\workspace\\boost_1_56_0" -O0 -g3 -pg -Wall -c -fmessage-length=0 -std=c++11 -pthread -o "src\\pid.o" "..\\src\\pid.cpp" 
g++ "-IC:\\Users\\kam\\workspace\\boost_1_56_0" -O0 -g3 -pg -Wall -c -fmessage-length=0 -std=c++11 -pthread -o "src\\main.o" "..\\src\\main.cpp" 
g++ -pg -o Hello_World.exe "src\\pid2.o" "src\\pid.o" "src\\main.o"  

result:

55

Now, if I make the functions in pid.c and pid2.c non-templated I do get the multiple definition error.

Kam
  • 5,878
  • 10
  • 53
  • 97
  • 3
    At a guess, it may be the multiple function definitions that the compiler alludes to when it uses the phrase "multiple function definitions". Just a guess, though. – Cheers and hth. - Alf Oct 16 '15 at 23:17
  • By the way, it's ungood practice to include `` in a header, because that forces the whole complex of supporting headers on client code. Instead, where practically possible, use [``](http://stackoverflow.com/questions/4300696/what-is-the-iosfwd-header). – Cheers and hth. - Alf Oct 16 '15 at 23:19
  • @Cheersandhth.-Alf I just through an example to illustrate a point; but thanks for the comment regardless. – Kam Oct 16 '15 at 23:20
  • This may depend on the specific command used to compile and link the code. Could you include that information? – jwd Oct 16 '15 at 23:23
  • If you switch the order of `pid.o` and `pid2.o` on the commandline, I expect you get different output. Is that the case? – jwd Oct 16 '15 at 23:30
  • @Barmar: that's not true as a general rule, only for weak symbols. Probably what you meant, but just clarifying. – jwd Oct 16 '15 at 23:44

1 Answers1

2

I'm guessing the linker isn't complaining because it doesn't know it's happening.

When you compile a particular instantiation of a function template in a translation unit, those functions are marked as weak symbols (using ELF terminology); when the linker sees multiple weak symbols with the same signature it removes all but one of the definitions.

The C++ standard requires that multiple definitions of inline/template functions are identical -- the famous One Definition Rule. This is why template and inline functions should always be defined in header files. The linker has no need to actually check that the function definitions are the same -- it assumes that you have abided by the rules and so it can pick any one of them. In this case it's picked the version that outputs 55, but it could just as easily have picked the other.

In any case, you are invoking undefined behaviour by providing two different definitions of the same template function, so you don't get to complain when the result doesn't match your expectations :-)

EDIT

Non-template, non-inline functions however are not marked as weak when they are compiled. In this case, only one translation unit (that is, one cpp file) may provide a definition. If you try defining the same non-template, non-inline function in two different object files then the linker will see the multiple "strong" definitions and give you an error.

As @jwd points out in the comments, in an ideal world the linker would be able do diagnose your original violation of the ODR, but doing so isn't really feasible unless you're using something like whole-program optimisation.

Tristan Brindle
  • 16,281
  • 4
  • 39
  • 82
  • I have seen the linker or compiler (can't remember) complaining about multiple definitions, when would that happen then? Also, if I make the above function non templated I get the multiple definition error (will update the question) – Kam Oct 16 '15 at 23:39
  • To add a little: in a perfect world, you might get a warning about this bad thing you did. But the toolchain you use (gcc in this case) is under no obligation to provide such a warning, w/regard to the C++ standard. – jwd Oct 16 '15 at 23:41
  • @Kam Non-template, non-inline functions are not marked as *weak*, so the linker will complain if there are two definitions with the same signature in two different object files. That's probably where you've seen it? – Tristan Brindle Oct 16 '15 at 23:42