0

I believe that there are 4 situations where my question may have different answers. These situations are sorted by member vs. non-member functions and within vs. without a library.

Non-member function within a library

Suppose that I have defined a template function func in header func.h.

// func.h

template <typename T>
int func(T t){
    //definition
}

I #include "func.h" in two cpp files of the same project/library/executable and call

//a.cpp
#include "func.h"

//stuff

int m = func<int>(3);

//stuff

and

//b.cpp
#include "func.h"

//stuff

int n = func<int>(27);

//stuff

My understanding is that these two cpp files should compile into their own object files. In what object file is func<int> instantiated? Why will the One Definition Rule not be violated? For this basic application of templates, is there any benefit to explicitly instantiating func<int> separate from its use?

Member function within a library

Suppose that func is instead a member function of some class Func.

// func.h

class Func {
    template <typename T>
    int func(T t){
        //definition
    }
};

Where will func be instantiated? Will func<int> be linked to or placed inline?

Member and Non-Member functions across libraries

Suppose that a.cpp and b.cpp are in different libraries that are compiled separately and later linked into an executable. Will the different libraries their own definitions of func<int>? At link time, why will the One Definition Rule not be violated?

Note: There is a related question of the same title here, but in a specific situation with one cpp file.

mana
  • 545
  • 4
  • 12
  • Does [Why C++'s templated class doesn't break one definition rule?](https://stackoverflow.com/a/34552418/7582247) answer your question? – Ted Lyngmo Oct 26 '20 at 20:09
  • [This function template instantiation reference](https://en.cppreference.com/w/cpp/language/function_template#Function_template_instantiation) might be good to read. – Some programmer dude Oct 26 '20 at 20:11
  • 1
    Reopening because that alleged duplicate was barely relevant. – Maxim Egorushkin Oct 26 '20 at 20:35
  • I read through the top answers in the suggested dupe. The answers were related and informative, but did not answer the question here. This question is not a duplicate of the suggested duplicate. The answers in the suggested duplicate do not answer this question. The answers to this question are not duplicates of the answers to the suggested duplicate. – mana Oct 26 '20 at 21:05
  • for non-member one, it violates ODR and should be tagged `inline`. the reason it works may be that the `func` is expanded by compiler. for member one, it's `inline` function automatically because it's in the class definition, so it doesn't violate ODR. – RedFog Oct 27 '20 at 02:57

2 Answers2

4

In what object file is func<int> instantiated?

In every object file (aka translation unit) that invokes it or takes an address of it when the template definition is available.


Why will the One Definition Rule not be violated?

Because the standard says so in [basic.def.odr].13.

Also see https://en.cppreference.com/w/cpp/language/definition

There can be more than one definition in a program of each of the following: class type, enumeration type, inline function, inline variable (since C++17), templated entity (template or member of template, but not full template specialization), as long as all of the following is true...


For this basic application of templates, is there any benefit to explicitly instantiating func<int> separate from its use?

In this case you get no inlining but possibly smaller code. If you use link-time code generation, then inlining may still happen.

Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
  • The dupe was perfectly fine, why did you reopen? All of that is already well answered there, and I was just about to add Ted's link to the duplicate list. There's nothing bad in having answered duplicates in the repo, that's just their purpose. – πάντα ῥεῖ Oct 26 '20 at 20:39
  • 1
    @πάνταῥεῖ The dupe was walls of somewhat related text, which one would have to somehow link to the questions here. That's not fine to me. – Maxim Egorushkin Oct 26 '20 at 20:40
1

All your questions do not really differ when it comes to answer. Regardless of template function being a member or a free function, it is going to be instantiated on first use (with given types) in each compilation unit (.cpp file).

From the compiler standpoint, ODR is not violated here, since there are no two prohibited definitions of templated function. Standard explicitly allows several definitions of templated functions.

Yet your intuition that you end up with definition of instantiated function twice in object files is correct. Luckily, ODR doesn't apply at this point. Instead, those definitions are generated with so-called 'weak' symbol - telling linker that those two symbols are identical, and it is free to pick one (or none and perform link-time optimization!)

SergeyA
  • 61,605
  • 5
  • 78
  • 137
  • Not my downvote. From linker perspective, there are multiple definitions of the same symbol in different translation units - an instantiated function. From standard's perspective linkers are an implementation detail of the C++ abstract machine. So, there do exists indeed multiple definitions of the same function in one program. But not necessarily in the source code. – Maxim Egorushkin Oct 26 '20 at 20:26
  • @MaximEgorushkin Yes, those are those SergeyA refers to being generated with the _weak symbol_ I assume? Multiple instances from one function template definition? I feel I'm still missing something. – Ted Lyngmo Oct 26 '20 at 20:32
  • @MaximEgorushkin I think, this is a valid point and my wording is not accurate. I will rephrase. – SergeyA Oct 26 '20 at 20:32
  • 2
    The notion that because the definition is okay because it appears physically only once, in a header file, is faulty. The header is irrelevant; the definition appears in two separate translation units. Appearing once in a header included in two source files is equivalent to appearing identically in two source files. So the fact that it is physically on disk only once is not the reason the One Definition Rule is not violated. The [other answer](https://stackoverflow.com/a/64544267/298225) gives a plausible reason: The C++ standard says so. Edit: This answer has now been updated regarding this. – Eric Postpischil Oct 26 '20 at 20:36
  • @EricPostpischil Thanks, I think that's where I got a bit lost. – Ted Lyngmo Oct 26 '20 at 20:40
  • @TedLyngmo Note that same source code - "each such definition shall consist of the same sequence of tokens...", is necessary but not sufficient, there are more requirements for ODR to not break. – Maxim Egorushkin Oct 26 '20 at 20:49
  • 1
    @MaximEgorushkin Thanks Maxim. I started reading a little @ [basic.def.odr/13](https://eel.is/c++draft/basic.def.odr#13) - the list just goes on and on :-) – Ted Lyngmo Oct 26 '20 at 20:55