2

If I will write something like this:

// A.h
#ifndef A_h
#define A_h
class A
{
public:
    void f();
};

void A::f()
{
}
#endif //A_h


// B.cpp
#include "A.h"

void foo()
{
    A a;
    a.f();
}


// C.cpp
#include "A.h"

void bar()
{
    A b;
    b.f();
}

// main.cpp
#include "B.cpp"
#include "C.cpp"
using namespace std;

int main()
{
    foo();
    bar();
    return 0;
}

I get a linker error as such:

error LNK2005: "public: void __thiscall A::f(void)" (?f@A@@QAEXXZ) already defined in B.obj

Why does the same problem not happen when the A class is a class template? Eventually it becomes a plain class (a non-template one) during compilation, right? For this reason, I expect the same behavior as a non-template class, i.e. a linker error.

Niall
  • 30,036
  • 10
  • 99
  • 142
Narek
  • 38,779
  • 79
  • 233
  • 389
  • This is not a duplicate for the marked question, despite the title question. This is about, given the template code in the header, why aren't there duplicate definitions resulting in linker errors, not why are there missing symbols. – Niall Apr 27 '16 at 17:48

3 Answers3

5

There are two separate effects at work here:

  1. A member function definition that's out of line is a normal function definition, and by one definition rule (ODR) it must occur precisely once in the link. A member function defined inline is implicitly inline, and the ODR allows inline function definitions to be repeated:

    That is, it's OK to put the following code in a header and include it repeatedly:

    struct Foo {
       void bar() {}   // "inline" implied
    };
    

    But if you have the definition out of line, it must be in a single translation unit.

  2. Function templates can be defined repeatedly, even when they are not inline. The templating mechanism in general already needs to deal with repeated instantiations of templates, and with their deduplication at link time.

    Member functions of class templates are themselves function templates, and therefore it doesn't matter whether you declare them inline.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • 1
    Why de-duplication at link time is not done for non-template classes? – Narek Apr 25 '16 at 13:19
  • @Narek: Because that's how it's always been :-) C didn't have deduplication, and C++ took over those same semantics. It only changed the semantics for the new features (templates) that didn't exist in C. – Kerrek SB Apr 25 '16 at 13:25
  • 1
    What I ask is exactly, why the implemented de-duplication feature is not used for ordinary classes too. It is already implemented, right? Just re-use and make peoples' life easier. This was my original question, Kerrek. – Narek Apr 25 '16 at 18:06
  • @Narek: Because that would be a change from how C worked, I suppose. – Kerrek SB Apr 25 '16 at 19:57
2

Why is it that the non template functions are treated differently to templates when it comes to multiple definitions?

There are historical and compatibility issues involved here. Some of the requirements come from C, that is the way it worked. There are also reasons related to what templates are, they are code generators; when required, the compiler needs to generate the code, consequently it needs to see the code when it generates it. This has a knock on effect that there will be multiple definitions, so rules are required to resolve those issues.

Simply put; templates behave (w.r.t. linking) as if they had a single definition in the program, hence they do not behave the same during compilation and linking as non-templates (that are not declared with inline) - in particular w.r.t. functions. If the non-templates are declared inline, similar behaviour is seen.


Standard references here include;

Some background, most of the issues here relate to linkage, what is linkage? §3.5/2 [basic.link]

A name is said to have linkage when it might denote the same object, reference, function, type, template, namespace or value as a name introduced by a declaration in another scope:

  • When a name has external linkage, the entity it denotes can be referred to by names from scopes of other translation units or from other scopes of the same translation unit.
  • When a name has internal linkage, the entity it denotes can be referred to by names from other scopes in the same translation unit.
  • When a name has no linkage, the entity it denotes cannot be referred to by names from other scopes.

Some general rules relating to functions and variable, for the program as a whole and each of the translation units.

§3.2/1 [basic.def.odr]

No translation unit shall contain more than one definition of any variable, function, class type, enumeration type, or template.

And

§3.2/4 [basic.def.odr]

Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program...

§3.2/6 [basic.def.odr]

There can be more than one definition of a class type (Clause [class]), enumeration type ([dcl.enum]), inline function with external linkage ([dcl.fct.spec]), class template (Clause [temp]), non-static function template ([temp.fct]), static data member of a class template ([temp.static]), member function of a class template ([temp.mem.func]), or template specialization for which some template parameters are not specified ([temp.spec], [temp.class.spec]) in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements....

If D is a template and is defined in more than one translation unit, then the preceding requirements shall apply both to names from the template's enclosing scope used in the template definition ([temp.nondep]), and also to dependent names at the point of instantiation ([temp.dep]). If the definitions of D satisfy all these requirements, then the behavior is as if there were a single definition of D. If the definitions of D do not satisfy these requirements, then the behavior is undefined.

Some informal observations on the above list including the classes, templates etc. These are typical elements often found in header files (of course not exclusively or limited to headers). They are given these special rules to make everything work as expected.

What about class member functions? §9.3 [class.mfct]

1/ A member function may be defined ([dcl.fct.def]) in its class definition, in which case it is an inline member function ([dcl.fct.spec]), or it may be defined outside of its class definition if it has already been declared but not defined in its class definition. A member function definition that appears outside of the class definition shall appear in a namespace scope enclosing the class definition...

2/ An inline member function (whether static or non-static) may also be defined outside of its class definition provided either its declaration in the class definition or its definition outside of the class definition declares the function as inline or constexpr. [ Note: Member functions of a class in namespace scope have the linkage of that class. Member functions of a local class ([class.local]) have no linkage. See [basic.link]. — end note ]

So basically, member functions not defined in the class definition and not implicitly inline, hence the "normal" rules apply and hence can only appear once in the program.

And template, what does it say about linkage ? §14/4 [temp]

A template name has linkage ([basic.link]). Specializations (explicit or implicit) of a template that has internal linkage are distinct from all specializations in other translation units... Template definitions shall obey the one-definition rule ([basic.def.odr]).

Niall
  • 30,036
  • 10
  • 99
  • 142
  • Didn't know that they are declared inline, but surely it can do the trick :D – Narek Apr 25 '16 at 13:05
  • If they are implicitly inlined, then an additional `inline` makes no sense, right? I'm not sure about implicit inlining. Cppreference just says that *At link time, identical instantiations generated by different translation units are merged.* Do you have a reference to the standard to prove the implicit inlining? – HolyBlackCat Apr 25 '16 at 13:09
  • @holyblackcat. There would be no need for the additional inline. That was the point of the original post. Ive simplified some of the wording, it was not meant to be a formal standard post, some has evolved along those lines. – Niall Apr 25 '16 at 16:19
  • @narek. I've added to the answer. They are not strictly inline, but they have a similar effect. The duplicates definitions are handled by the linker as if there was a single definition. Some testing shows some compilers chose the first, ultimately it doesn't matter which is chosen, since they all need to be the same anyway. – Niall Apr 27 '16 at 06:27
0

Templates are not code; they are patterns for creating code. They must be visible wherever they are used, so the compiler has to have special rules for using them. The key special rules here are that the compiler generates code wherever a template is used and that the linker ignores duplicates.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165